Skip to content
Docs / StateMirror
DOCUMENT / STATEMIRROR

Application Patterns

Use one evidence record to preserve the facts your application consulted. These are application-owned patterns using Core’s HTTP API. Core does not supply provider connectors or execute the decisions shown here.

Billing, access and expiry extend the existing evidence scenarios. All values below are illustrative; the payload shapes and Evidence Lanes are optional.

TYPE
Integration recipes

Submission and retry recipe

#

Save one pattern’s payload as state_payload inside the envelope below. Use a specific application decision reference, its capture time and a fresh idempotency key. The complete access envelope is shown here so the example can be run against your local Quickstart service.

RECIPE / ENVELOPE / JSONevidence.json
{
  "evidence_ref": "access:customer_123:request_001",
  "evidence_type": "access_decision",
  "captured_at": "2026-06-15T18:22:31.000Z",
  "state_payload": {
    "subject": "customer_123",
    "inputs": {
      "plan_status": "active",
      "seats_used": 10,
      "seat_limit": 10,
      "read_at": "2026-06-15T18:22:30.000Z"
    },
    "rule_version": "access-rules@2026.06.12",
    "decision": "deny",
    "reason": "seat_limit_reached",
    "correlation_id": "request_001"
  }
}
Save as evidence.json. For another pattern, replace state_payload, evidence_ref, evidence_type and captured_at with that decision’s values.
RECIPE / HTTP / BASH / CURLSUBMIT_AND_RETRIEVE
# Set these to your local pilot service and service credentials.
CORE_URL='http://localhost:8080'
WRITE_KEY='YOUR_WRITE_KEY'
READ_KEY='YOUR_READ_KEY'
curl --fail-with-body -X POST "$CORE_URL/v1/snapshots" \
  -H "Authorization: Bearer $WRITE_KEY" \
  -H 'Idempotency-Key: access-customer-123-request-001' \
  -H 'Content-Type: application/json' \
  --data-binary @evidence.json

# Save the returned ID with your request/invoice reference.
SNAPSHOT_ID='PASTE_RETURNED_ID'
curl --fail-with-body "$CORE_URL/v1/snapshots/$SNAPSHOT_ID" \
  -H "Authorization: Bearer $READ_KEY"
curl --fail-with-body "$CORE_URL/v1/snapshots/$SNAPSHOT_ID/verify" \
  -H "Authorization: Bearer $READ_KEY"
Inspect response bodies as well as HTTP status. A verification request can succeed with valid: false.

Each pattern below uses this submission flow. Retry the identical submission with the same key after an uncertain response. Use a new key for each new decision. Handle conflicting reuse explicitly; review cleanup timing and failure behavior. The application owns capture ordering and any durable retry mechanism.

Billing quantity

#
Inputs
Active subscription, ten billable seats, invoice period and the billing rule version.
Decision
The application calculates a ten-seat charge. Payment execution remains outside StateMirror.
PATTERN / BILLING / JSONSTATE_PAYLOAD
{
  "subject": "customer_123",
  "invoice_ref": "invoice_001",
  "inputs": {
    "subscription_status": "active",
    "billable_seats": 10,
    "period": "2026-06",
    "read_at": "2026-06-15T18:22:30.000Z"
  },
  "rule_version": "billing-rules@2026.06.12",
  "decision": "charge_ten_seats"
}
Application-defined state_payload. Submit through the shared envelope and HTTP recipe above.

Later investigation: Retrieve the saved snapshot when the invoice is disputed after seats drop to six. Inspect the historical quantity, period and rule version; verify integrity. Consult payment records separately to establish whether a charge executed.

Entitlement denial

#
Inputs
Active plan, ten occupied seats and a ten-seat entitlement.
Decision
The application denies an additional seat under its access rules.
PATTERN / ACCESS / JSONSTATE_PAYLOAD
{
  "subject": "customer_123",
  "inputs": {
    "plan_status": "active",
    "seats_used": 10,
    "seat_limit": 10,
    "read_at": "2026-06-15T18:22:30.000Z"
  },
  "rule_version": "access-rules@2026.06.12",
  "decision": "deny",
  "reason": "seat_limit_reached",
  "correlation_id": "request_001"
}
Application-defined state_payload. Submit through the shared envelope and HTTP recipe above.

Later investigation: After a plan upgrade, retrieve by the original request reference and verify the submitted ten-of-ten seat count. Today’s plan does not establish the inputs used by the original request.

Trial expiry

#
Inputs
The expiry timestamp and the application’s evaluation time, both in UTC.
Decision
The application limits the account to basic features because the evaluation time is after expiry.
PATTERN / EXPIRY / JSONSTATE_PAYLOAD
{
  "subject": "customer_123",
  "inputs": {
    "expires_at": "2026-06-15T18:00:00.000Z",
    "evaluated_at": "2026-06-15T18:22:30.000Z",
    "signal": "expired"
  },
  "rule_version": "expiry-rules@2026.06.12",
  "decision": "downgrade_to_basic"
}
Application-defined state_payload. Submit through the shared envelope and HTTP recipe above.

Later investigation: After support extends the trial, retrieve and verify the original timestamps. Compare with the extension record. StateMirror preserves the application’s time observations; it does not establish clock accuracy.

External provider state

#
Inputs
The provider response actually consulted, its source version when known and when the application read it.
Decision
The application grants a subscription feature based on the active status it observed.
PATTERN / PROVIDER / JSONSTATE_PAYLOAD
{
  "subject": "customer_123",
  "inputs": {
    "subscription_status": "active",
    "source": "billing-provider",
    "source_updated_at": "2026-06-15T18:20:00.000Z",
    "read_at": "2026-06-15T18:22:30.000Z"
  },
  "rule_version": "subscription-rules@2026.06.12",
  "decision": "grant_feature"
}
Application-defined state_payload. Submit through the shared envelope and HTTP recipe above.

Later investigation: If the provider later reports cancellation, inspect the preserved read time and source update time. The response may have been stale. Evidence proves neither provider truth nor that the response was fresh.

Rule versioning

#
Inputs
A configuration revision and the concrete threshold used by the application.
Decision
The application denies another seat under that revision.
PATTERN / RULES / JSONSTATE_PAYLOAD
{
  "subject": "customer_123",
  "inputs": {
    "seats_used": 10,
    "seat_limit": 10,
    "configuration_revision": "entitlements-42"
  },
  "rule_version": "access-rules@2026.06.12",
  "decision": "deny",
  "reason": "seat_limit_reached"
}
Application-defined state_payload. Submit through the shared envelope and HTTP recipe above.

Later investigation: Compare the recorded revision and threshold with the rule artifact retained by your application team. StateMirror does not archive, execute or replay the referenced rule code.

A denial investigated 21 days later

#

Illustrative lifecycle, not a customer case study. It uses the same access evidence as the Quickstart and Workbench.

  1. Day 0: the application reads ten occupied seats against a ten-seat limit, denies another seat and submits the access envelope. It stores the returned snapshot ID with request_001.
  2. Day 21: the customer disputes the denial. Their plan has since been upgraded and a member removed. Current state permits access.
  3. Retrieve: support locates the saved ID. If only the original reference is available, query GET /v1/snapshots?evidence_ref=access%3Acustomer_123%3Arequest_001 with a read bearer key, then select the relevant returned ID.
  4. Inspect and verify: inspect the ten-of-ten counts and rule version. Call the snapshot verification endpoint; in this intact example, valid is true. If it fails, investigate preservation integrity before relying on the record.
  5. Conclude: the application submitted facts showing its seat limit was reached at that moment. Check rule code and upstream records separately to assess whether those facts and the denial were correct.

The investigation avoids rebuilding the submitted context from current rows. It does not establish that ten seats were externally true or that enforcement succeeded.

Trace the evidence lifecycle → · Pilot one of your own decisions →