Testing Stateful APIs with Drift
Many APIs appear to require multiple steps to test. For example:
Creating a user before testing
GET /users/{id}Running
POST /checkout/orders/{id}before checking/checkout/status/{id}Polling until a job completes
These patterns suggest workflow testing. Drift is not a workflow engine. Drift focuses on contract conformance by testing each operation independently, with the required state prepared in advance.
This page explains the core concept behind testing stateful and async APIs with Drift.
What "Stateful" Means in Drift
A stateful API is one whose response depends on prior conditions. Examples include:
A resource that may or may not exist
An async job that moves from pending → ready → completed
Feature flags or modes that change response shapes
Drift fully supports testing these scenarios. What Drift does not do is run a sequence of API calls to reach those states.
Drift tests states, not flows.
Why Teams Expect Sequential Tests
Developers often assume that a test must produce state before checking it:
To test
GET /users/{id}, I must callPOST /usersfirst.To test
/checkout/status/{id}, I need to runPOST /checkout/orders/{id}first.
This instinct is natural, but it comes from functional testing, where flows are executed end-to-end. Contract testing has a different purpose.
Contract tests must be:
isolated
deterministic
fast
independent of side effects
Chaining steps introduces nondeterminism and hides bugs. Drift avoids these problems by treating each state as a separate scenario.
How Drift Handles Stateful Behavior
Drift verifies the behavior of each operation exactly as described in the OpenAPI specification. To support stateful scenarios, Drift relies on state injection, not sequential calls.
Not supported: workflow execution
POST /checkout/orders/{id} → extract ID
HEAD /checkout/status/{id} → poll
GET /result/{id}Supported: state-based verification
Prepare state → call /checkout/status/{id} → validate documented responseEach test is independent and validates one defined state.
How to Inject State for Contract Tests
State is prepared before Drift calls your real API. Common approaches include:
Lua hooks - call helper endpoints or internal tools to set state
Non‑production helper endpoints - explicitly create or modify state
Datasets - provide stable IDs or static records
Seeded or mocked environments - e.g., workers or job runners preconfigured for specific states
This allows Drift to test stateful behavior without executing workflows.
Example: Asynchronous Request-reply APIs
Async APIs often follow this pattern:
POST /checkout/orders/{id}→ returns a job ID (202 Accepted)HEAD /checkout/status/{id}→ returns job status (pending, ready, completed)GET /result/{id}→ returns final output
Instead of chaining these operations:
Test
POST /checkout/orders/{id}independentlyTest each
/checkout/status/{id}state independentlyTest
GET /result/{id}independently
Each test prepares the required state ahead of time.
Full Example: Abstract Async Workflow
This expanded example shows how state-based contract testing applies to an asynchronous workflow. It is loosely based on the PactFlow AI architecture, with internal systems such as storage, authentication, and workers represented as a single Processing Service for brevity.

How Drift Tests These States
Drift does not reproduce this workflow. Instead, it creates four independent contract tests:
POST /generate→ 202 Accepted — validates the job tokenGET /status/{id}→ 202 Pending — state prepared via Lua or helper endpointGET /status/{id}→ 200 Ready — job pre‑set to readyGET /result/{id}→ 200 OK — outputs pre‑seeded
Each test validates only the response defined in the OpenAPI specification for that state.
Summary
Drift tests contract conformance, not workflow logic
Drift supports stateful testing through state injection, not chaining
Stateful and async flows become independent state scenarios
Use functional or integration tests for full workflow execution
To apply these ideas in practice, see Testing APIs with State Dependencies.