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

Match Lifecycle Status

The Match Lifecycle Status (lifecycleStatus) access rule is a semantic-aware attribute rule designed for entities with a lifecycle state machine. It restricts access to resources based on whether their status is permitted by an allow list (allowedStatuses) or blocked by a deny list (deniedStatuses).

Unlike generic attribute matching, Match Lifecycle Status automatically detects the property tagged with the Status semantic module on the target entity.


  • Semantic Status Binding: Automatically binds to the entity property annotated with the Status semantic module without needing manual column selection.
  • Dual-Phase Execution:
    • Collection Actions (list, search) in FETCH Phase: Automatically injects SQL WHERE status IN (...) or WHERE status NOT IN (...) clauses into the query.
    • Single-Record Actions (read, update, delete) in POST_FETCH Phase: Inspects the hydrated record’s status in memory before executing the mutation or returning data.
  • Deny-First Evaluation: If both deniedStatuses and allowedStatuses are specified, the deny list is evaluated first for maximum security.
  • Separation from Creation Gating: This access rule evaluates existing records (FETCH and POST_FETCH). Constraining which states are allowed when creating new records is handled at the data layer by the Status semantic module (initialStatuses and default values).
PropertySpecification
Rule TypelifecycleStatus
Identity Constrainingfalse (Must be paired with an identity rule in the same scenario)
Supported StrategiesAll strategies (RBAC, OrganizationRBAC, EnterpriseRBAC)
Allowed Placement LevelsExposed Entity Level (exposure), Action Level (action) (Not allowed at global API Model Level)
Execution PhasesFETCH (list, search, restore), POST_FETCH (read, update, delete, link, unlink)

When configuring Match Lifecycle Status, you can specify allow lists, deny lists, or both:

An array of status values permitted for this action.

  • Example: allowedStatuses: ['published']
  • Behavior:
    • list/search: Injects WHERE status IN ('published').
    • read/update: Denies (403 Forbidden) if the record status is not 'published'.

An array of status values explicitly forbidden for this action.

  • Example: deniedStatuses: ['archived', 'banned']
  • Behavior:
    • list/search: Injects WHERE status NOT IN ('archived', 'banned').
    • read/update: Denies (403 Forbidden) if the record status matches any denied value.

When a team member browses or filters a collection of records (such as an editorial dashboard or support queue), two filters work together at the same time:

  1. The Security Rule (Access Rule): The permission boundary configured in API Now for their role. For example, an Editorial Reviewer might be permitted to see records in two active states: in_review and published (allowedStatuses: ['in_review', 'published']).
  2. The User’s Search Filter (URL Query Parameter): What the reviewer specifically asks to see in their dashboard right now (for example: GET /articles?status=in_review).

The database combines both rules using AND logic: records are only returned if they match what the reviewer asked for AND what their security role permits.

Scenario A: Filtering for One of Their Permitted Statuses

Section titled “Scenario A: Filtering for One of Their Permitted Statuses”

The reviewer wants to focus only on articles waiting for review and filters their dashboard with GET /articles?status=in_review:

  • What the reviewer requested: status = 'in_review'
  • What their role permits: status IN ('in_review', 'published')
  • What the database looks for:
    SELECT * FROM articles
    WHERE (status = 'in_review')
    AND (status IN ('in_review', 'published'))
  • Result: Success (200 OK). The query narrows down the list and returns only the articles currently in review. The reviewer sees exactly what they asked for.

Scenario B: Filtering for a Status Outside Their Permissions

Section titled “Scenario B: Filtering for a Status Outside Their Permissions”

The reviewer tries to filter for writers’ early personal drafts by requesting GET /articles?status=draft:

  • What the reviewer requested: status = 'draft'
  • What their role permits: status IN ('in_review', 'published')
  • What the database looks for:
    SELECT * FROM articles
    WHERE (status = 'draft')
    AND (status IN ('in_review', 'published'))
  • Result: Empty list [] (200 OK). Because no article can simultaneously be a draft and also be in_review or published, the query simply finds zero matching items.

What Happens When Opening a Specific Record Directly?

Section titled “What Happens When Opening a Specific Record Directly?”

Unlike search lists, if the reviewer tries to open a specific private record directly by its unique link or ID (such as GET /articles/art_10293 when that article is in draft):

  • The system loads that specific record.
  • It checks whether the reviewer’s role is allowed to view records in draft status.
  • Because reviewers cannot view drafts, the request is immediately blocked with 403 Forbidden.

  • Status Semantic Module: Exactly one property on the target entity must be tagged with the Status semantic module in your Data Domain (e.g. Article.status with values draft, in_review, published, archived).

Pattern 1: Multi-Tier Content Visibility (Public vs. Reviewers vs. Admins)

Section titled “Pattern 1: Multi-Tier Content Visibility (Public vs. Reviewers vs. Admins)”

Expose public content while allowing editorial staff to view review pipelines on the exact same GET /articles endpoint:

Article.list Scenarios:
├── Scenario 1 (Admin Full View):
│ └── Match User Role: ['admin'] <- Admins see all records
├── Scenario 2 (Editorial Reviewers):
│ ├── Match User Role: ['editor', 'reviewer']
│ └── Match Lifecycle Status: allowedStatuses: ['in_review', 'published']
└── Scenario 3 (Public Readers):
├── Allow Public
└── Match Lifecycle Status: allowedStatuses: ['published'] <- Public sees published only

Pattern 2: Write-Locking Finalized Records (deniedStatuses)

Section titled “Pattern 2: Write-Locking Finalized Records (deniedStatuses)”

Prevent authors from modifying invoices or documents once they reach a finalized or immutable state (e.g. paid, archived, settled):

graph TD
    subgraph "Invoice.update Endpoint"
        S1["Scenario 1: Match User Role (finance_admin)"] --> Adm["Admins can edit any invoice"]
        S2["Scenario 2: Match Resource Owner + denied: [paid, void]"] --> Owner["Author can edit unpaid invoices"]
        Blocked["Author tries to edit paid invoice"] --> Denied["403 Forbidden"]
    end

Allow authors to delete their own articles only while in draft state. Once submitted or published, deletion requires an administrator:

Article.delete Scenarios:
├── Scenario 1 (Admin Override):
│ └── Match User Role: ['admin'] <- Admins delete any article
└── Scenario 2 (Author Drafts Only):
├── Allow Authenticated
├── Match Resource Owner (author)
└── Match Lifecycle Status: allowedStatuses: ['draft'] <- Authors delete drafts only

Caller StateResource Lifecycle StatusResulting HTTP Status
Anonymous (Public Scenario)Status is in allowedStatuses (e.g. published)200 OK
Anonymous (Public Scenario)Status is NOT in allowedStatuses (e.g. draft)403 Forbidden
Author (Draft Scenario)Author tries to edit a record with status in deniedStatuses (e.g. archived)403 Forbidden
Admin (Admin Scenario)Record is in any status200 OK / 204 No Content
Resource Not FoundRecord ID does not exist404 Not Found