Skip to content
API Now! is currently in closed beta. We are constantly updating these guides as we release updates!

Status (Semantic Module)

← Back to Modules Reference

In modern business applications, data rarely exists in a static state. An article moves from a draft to editorial review, publication, and eventual archival. An order moves from placed to fulfilled to completed. A support ticket progresses from open to in-progress to resolved.

The Status semantic module brings lifecycle workflow management directly to your data model. It transforms a standard text property with predefined choices into an active lifecycle state machine.

Instead of writing custom backend code or database triggers, you configure your business lifecycle declaratively:

  • Predefined States: The valid choices defined directly on the property (such as draft, submitted, in_review, published, and archived).
  • Default Starting State: The automatic starting state assigned when a record is newly created without a specified status.
  • Allowed Initial States: Which states callers are permitted to choose when creating a new record (preventing callers from bypassing early workflow stages).
  • Permitted State Transitions: The step-by-step roadmap of allowed next states (preventing illegal workflow jumps).
  • Terminal States: Final, closed states where a record’s lifecycle concludes and no further status modifications are permitted.

The platform automatically validates every creation and update request against these rules. If an API client attempts an illegal transition or tries to modify a finalized record, the request is safely rejected with clear, actionable HTTP 422 Unprocessable Entity feedback.


AttributeSpecification
ScopeProperty (Applied directly to a single entity property)
Data TypeString (Text) with predefined values (choices / enum)
MultiplicitySingle value only (scalar). Records cannot have multiple statuses simultaneously.
Entity FrequencyMaximum 1 Status property per entity across its entire hierarchy.
Database IndexingMandatory. Status properties must be marked as indexed to ensure fast query filtering.
Valid States SourceThe property’s predefined values list.
Default State SourceThe property’s standard default value setting.
Authorization IntegrationAuto-detected by the Match Lifecycle Status access rule in the API Modeler.

The valid states for your lifecycle come directly from the list of predefined choices configured on the property.

The starting state is defined using the property’s standard Default Value setting (for example, draft). When an API client creates a record without providing a status, the system automatically assigns this default value.

2. Restricting Creation States (initialStatuses)

Section titled “2. Restricting Creation States (initialStatuses)”

By default, if no initial states are specified, an API client can create a new record in any valid predefined state.

In many business workflows, however, records must begin in a specific starting stage:

  • Editorial Review: An author should only be able to create articles in draft, not directly in published.
  • Invoicing: A bill should start as draft or pending_approval, not paid.

By configuring Allowed Initial States, you specify the subset of states accepted during record creation (POST). Any attempt to create a record with an unapproved initial state is rejected with an HTTP 422 Unprocessable Entity error.

3. Permitted State Transitions (transitions)

Section titled “3. Permitted State Transitions (transitions)”

The state transition map defines the directed roadmap of valid next steps from each current state:

stateDiagram-v2
    [*] --> draft : Initial State on Create
    draft --> submitted : Submit for Review
    submitted --> in_review : Start Review
    submitted --> draft : Return for Edits
    in_review --> published : Approve & Publish
    in_review --> draft : Reject to Draft
    published --> draft : New Revision
    published --> archived : Archive Content
    archived --> [*] : Terminal (Locked)
  • Step-by-Step Validation: When an API client updates a record’s status, the system checks whether the new status is an approved next step for the current state.
  • Preventing Workflow Bypasses: If an article is currently in draft, an attempt to update its status directly to published is rejected because published is not in the allowed next steps for draft.
  • Flexible Workflows & Cycles: Workflows can branch into multiple directions or loop cyclically. For example, a published article can transition back to draft when starting a revision.
  • Open Transitions: If no transition rules are configured, records can transition freely between any of the property’s predefined states.

Terminal states represent permanent end-of-lifecycle stages (such as archived, cancelled, or closed):

  • Write Locking: Once a record enters a terminal state, its status field is locked against any further modifications.
  • Immediate Rejection: Any update request attempting to change the status of a terminal record is rejected with an HTTP 422 Unprocessable Entity error.
  • Completely Optional: Lifecycles without permanent dead-ends (such as continuous cyclic workflows) do not require terminal states.

It is important to understand the distinct roles of the Status semantic module and API Access Rules:

ConceptPurposeWhere It Is ConfiguredHow It Behaves
Status Semantic ModuleWorkflow Integrity & TransitionsData Domain Modeler (on the entity property)Answers: “Is this state transition physically and logically valid according to business rules?” Evaluates submitted data during record creation and updates.
Match Lifecycle StatusPermissions & VisibilityAPI Modeler (on exposed endpoints & actions)Answers: “Who is allowed to view, edit, or delete records that are currently in this state?” Evaluates caller identity and injects database filters.
  1. The State Machine (Status Module) defines that an article can legally transition from in_review to published.
  2. The API Access Rule (Match Lifecycle Status) ensures that only callers with the editor role can invoke the endpoint when the article is in in_review, while public callers can only see records in published.

Operational permissions (such as which roles can edit or view records in a given state) are managed in API Access Rules, keeping your data model clean, reusable, and decoupled from authentication strategies.


The runtime enforces your lifecycle rules consistently across all API operations:

  • Status omitted: The system automatically assigns the property’s default value (201 Created).
  • Explicit null submitted: The request is rejected with HTTP 422 Unprocessable Entity ("The field 'status' cannot be set to null.").
  • Disallowed initial status submitted: If initial states are configured and the submitted value is not among them, the request is rejected with HTTP 422 Unprocessable Entity.
  • Valid initial status submitted: The record is created with the requested status (201 Created).

Record Modification (PATCH / PUT /resources/:id)

Section titled “Record Modification (PATCH / PUT /resources/:id)”
  • Status omitted: The record’s status remains unchanged; other properties update normally (200 OK).
  • Status unchanged: Submitting the current status is treated as a safe, idempotent operation (200 OK).
  • Explicit null submitted: The request is rejected with HTTP 422 Unprocessable Entity.
  • Record currently in a terminal state: Any attempt to modify the status is rejected with HTTP 422 Unprocessable Entity ("Cannot transition from terminal status 'archived'.").
  • Invalid transition attempted: If the new status is not listed in the transitions map for the current status, the request is rejected with HTTP 422 Unprocessable Entity.
  • Legacy or uninitialized records: If an existing database record does not have a status set, an update that omits status automatically initializes it with the default value, while an update that supplies a status validates it as an initial assignment.

In this example, an Article entity defines a status property with choices draft, submitted, in_review, published, and archived:

  • Default Value: draft
  • Allowed Initial States: ['draft']
  • Transitions:
    • draft → ['submitted']
    • submitted → ['in_review', 'draft']
    • in_review → ['published', 'draft']
    • published → ['draft', 'archived']
  • Terminal States: ['archived']

1. Creating a Record with the Default Status

Section titled “1. Creating a Record with the Default Status”

When an author creates a new article without providing a status:

POST /articles
Content-Type: application/json
{
"title": "Designing Data Semantics"
}

The system automatically assigns the default status draft:

HTTP/1.1 201 Created
Content-Type: application/json
{
"data": {
"id": "art_101",
"title": "Designing Data Semantics",
"status": "draft"
}
}

2. Attempting an Unauthorized Initial Status

Section titled “2. Attempting an Unauthorized Initial Status”

A caller attempts to create an article directly in the published state, bypassing the review process:

POST /articles
Content-Type: application/json
{
"title": "Unreviewed Article",
"status": "published"
}

The system blocks the request:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"type": "https://docs.apinow.app/errors/validation",
"title": "Validation Error",
"status": 422,
"code": "VALIDATION_ERROR",
"detail": "Field validation failed",
"errors": [
{
"field": "status",
"message": "Invalid initial status: 'published'. Allowed initial statuses: 'draft'."
}
]
}

The author submits their draft for review:

PATCH /articles/art_101
Content-Type: application/json
{
"status": "submitted"
}

Because draft → submitted is an approved transition path, the update succeeds:

HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"id": "art_101",
"title": "Designing Data Semantics",
"status": "submitted"
}
}

A client attempts to move an article directly from submitted to archived:

PATCH /articles/art_101
Content-Type: application/json
{
"status": "archived"
}

The transition is rejected because archived is not an allowed next step from submitted:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"type": "https://docs.apinow.app/errors/validation",
"title": "Validation Error",
"status": 422,
"code": "VALIDATION_ERROR",
"detail": "Field validation failed",
"errors": [
{
"field": "status",
"message": "Invalid status transition from 'submitted' to 'archived'. Valid transitions: 'in_review', 'draft'."
}
]
}

An article has reached the archived state. A client attempts to return it to draft:

PATCH /articles/art_101
Content-Type: application/json
{
"status": "draft"
}

The engine blocks the modification because archived is a terminal state:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"type": "https://docs.apinow.app/errors/validation",
"title": "Validation Error",
"status": 422,
"code": "VALIDATION_ERROR",
"detail": "Field validation failed",
"errors": [
{
"field": "status",
"message": "Cannot transition from terminal status 'archived'."
}
]
}

Data Modeling Best Practices & Validation Rules

Section titled “Data Modeling Best Practices & Validation Rules”

1. The Single Status Rule (No Multiple Statuses)

Section titled “1. The Single Status Rule (No Multiple Statuses)”

The platform enforces that an entity can have at most one property tagged with the Status semantic module across its entire inheritance tree.

  • Why this rule exists: A state machine requires a record to occupy exactly one lifecycle state at any point in time. If an entity could have multiple status properties or multiple status values, the system could not determine which transitions apply, what happens during updates, or which state protects the record in access rules.
  • Direct Properties: You cannot tag two fields on the same entity with Status (for example, attempting to apply Status to both order_status and payment_status on the same entity will trigger a validation error).
  • Inherited Properties & Shadowing: If an entity inherits from a parent entity that already defines a Status property (such as Article extending ContentItem), it automatically shares that status. The child entity cannot define a second, differently named status field, nor can an entity inherit conflicting status properties from multiple parents. However, a child entity can shadow (override) the parent’s status property by declaring a property with the exact same name if it needs to customize the allowed states or state transitions specifically for that child entity.
  • Single Value (Scalar) Only: A status property must be single-valued (scalar). It cannot be configured as a list or array (multiple: true). For records that require multiple classification labels, use Categories or Tags instead.

2. How to Model Independent Business Lifecycles

Section titled “2. How to Model Independent Business Lifecycles”

In real-world applications, a single business transaction might involve multiple processes that happen in parallel. For example, an e-commerce order tracks:

  • Fulfillment Pipeline: placed → processing → shipped → delivered
  • Payment Pipeline: unpaid → authorized → paid → refunded

Because an entity can only have one Status property, choose one of these recommended approaches:

  • Approach A (Recommended): Model as Separate Entities: Create an Order entity with a fulfillment_status (tagged with Status), and a related Payment entity with a payment_status (tagged with Status). This represents the real-world domain cleanly and gives each entity its own dedicated state machine.
  • Approach B: Primary Status + Standard Choice Property: Tag the primary business workflow (e.g. fulfillment_status) with the Status module, and keep the secondary workflow (e.g. payment_status) as a standard text property with predefined choices (enum) without the Status module.
  • Mandatory Indexing: Always ensure database indexing is enabled (index: true) on your status property. Because status fields are actively filtered in collection queries and evaluated by authorization rules, indexing guarantees fast queries and avoids slow table scans.
  • Align Default and Initial States: When configuring an initial states list, make sure the property’s default value is one of those initial states so automatic record creation succeeds.
  • Reserve Terminal States for True Dead-Ends: If records can ever be reopened or recycled, omit terminal states and use cyclic transitions instead.