Arazzo: The Missing Piece for AI-Assisted API Consumption
You’ve built an API. You’ve written the OpenAPI spec. You’ve even generated some SDK clients. And yet, your support inbox is full of “how do I…?” questions. Developers can see your endpoints but don’t understand how to chain them together.
Sound familiar? That’s the problem Arazzo solves.
The Problem with API Documentation Today
Think about a typical e-commerce API. It has endpoints for authentication, product search, cart management, checkout, and payment. Your OpenAPI spec documents each one beautifully—request parameters, response schemas, error codes.
But here’s what it doesn’t tell you:
- Do I authenticate before searching, or after adding to cart?
- Can I checkout without a shipping address, or will it fail silently?
- What happens if payment fails—do I need to recreate the cart?
- Which order ID do I pass from the checkout response to the payment endpoint?
These are the questions that turn a 5-minute integration into a 2-day ordeal. The answers exist—scattered across tutorials, sample code, and support tickets. But they’re not machine-readable. They’re not standardized. They’re not specifications.
Enter Arazzo: Workflows as Specification
Arazzo, released by the OpenAPI Initiative in May 2024 (with version 1.0.1 in January 2025), fills this gap. It’s a specification for describing how to chain API calls together to achieve a specific outcome.
Think of it this way:
- OpenAPI: “Here are the LEGO bricks”
- Arazzo: “Here’s how to build the castle”
An Arazzo description defines:
- Steps: A sequence of API calls to execute
- Dependencies: Which step must complete before another begins
- Data flow: How to pass values from one response to the next request
- Success criteria: What determines if a step succeeded
- Failure handling: What to do when things go wrong
The specification is both human-readable and machine-readable—which means both developers AND their AI assistants can understand it.
Anatomy of an Arazzo Workflow
Let me walk you through the structure. An Arazzo document starts with metadata and references to the APIs it orchestrates. Let’s say we have an OpenAPI spec for a pet adoption service. The Arazzo document begins like this:
arazzo: 1.0.1info: title: Pet Adoption Workflow version: 1.0.0 description: | This workflow guides you through adopting a pet. Each step depends on the successful completion of the previous one.
sourceDescriptions: - name: petAdoptionAPI url: ./openapi.yaml type: openapiThen comes the workflow definition with its ordered steps:
workflows: - workflowId: pet-adoption-workflow summary: Complete pet adoption process description: | To adopt a pet, you need to: 1. Search for available pets 2. Pass a background check 3. Complete training 4. Finalize the adoptionSteps and Operations
Each step references an operation from your OpenAPI spec:
steps: - stepId: search-pets operationId: petAdoptionAPI.searchPets parameters: - name: type in: query value: $inputs.petTypeSuccess Criteria
You can define what “success” means for each step—not just HTTP 200:
- stepId: background-check operationId: petAdoptionAPI.submitBackgroundCheck successCriteria: - condition: $statusCode == 201 - context: $response.body condition: $.status == 'approved' type: jsonpathThis says: The step succeeds when we get a 201 status AND the response body's status field equals 'approved'.. It’s more expressive than just checking status codes.
Data Flow Between Steps
Here’s where Arazzo shines—runtime expressions that wire outputs to inputs:
- stepId: adopt-pet operationId: petAdoptionAPI.adoptPet parameters: - name: petId in: path value: $inputs.petId - name: ownerId in: path value: $inputs.ownerIdThe $inputs.petId expression references an input parameter provided when starting the workflow. Arazzo supports expressions for:
$inputs.*- Workflow input parameters$steps.*.outputs.*- Outputs from previous steps$response.body#/path- JSON Pointer into response bodies$response.header.*- Response headers$statusCode- HTTP status code
Failure Handling
Real workflows need to handle failures. Arazzo provides onFailure actions:
- stepId: background-check operationId: petAdoptionAPI.submitBackgroundCheck onFailure: - name: backgroundCheckFailed type: end - name: retryBackgroundCheck type: retry retryAfter: 5 retryLimit: 3 criteria: - condition: $statusCode == 503This defines two failure handlers: end the workflow if the check fails, but retry up to 3 times if we get a 503 (service unavailable). We can also imagine more complex error handling strategies with special cases where you will need to call alternative endpoints or notify users.
Putting It All Together
Now that we’ve seen the individual pieces, let’s look at the complete workflow. I built a demo API for pet adoption with this business logic:
- Search for available pets by type (cats or dogs)
- Background check the prospective owner (80% pass rate, 20% fail)
- Training certification for the owner
- Adoption finalization
arazzo: 1.0.1info: title: Pet Adoption Workflow version: 1.0.0
sourceDescriptions: - name: petAdoptionAPI url: ./openapi.yaml type: openapi
workflows: - workflowId: pet-adoption-workflow inputs: type: object properties: petType: type: string enum: [cat, dog] petId: type: string ownerId: type: string steps: - stepId: search-pets operationId: petAdoptionAPI.searchPets parameters: - name: type in: query value: $inputs.petType successCriteria: - condition: $statusCode == 200 outputs: availablePets: $response.body
- stepId: background-check operationId: petAdoptionAPI.submitBackgroundCheck parameters: - name: ownerId in: path value: $inputs.ownerId successCriteria: - condition: $statusCode == 201 - context: $response.body condition: $.status == 'approved' type: jsonpath onFailure: - name: backgroundCheckFailed type: end
- stepId: training operationId: petAdoptionAPI.completeTraining parameters: - name: ownerId in: path value: $inputs.ownerId successCriteria: - condition: $statusCode == 201
- stepId: adopt-pet operationId: petAdoptionAPI.adoptPet parameters: - name: petId in: path value: $inputs.petId - name: ownerId in: path value: $inputs.ownerId successCriteria: - condition: $statusCode == 200 outputs: adoptionId: $response.body#/id
outputs: adoptionId: $steps.adopt-pet.outputs.adoptionIdThis is executable documentation. The workflow declares inputs, chains data through steps, validates success criteria, handles failures, and exposes outputs—all in a format that both humans and machines can read.
Generating Client Code with AI
If you publish an API, Arazzo explains clearly how to use your API in different scenarios. It is enough for an AI coding assistant to read both the Arazzo and OpenAPI specs and generate correct client code that implements the workflow, including error handling and data dependencies.
Let me show you. With the pet adoption API running locally, I asked my AI coding assistant:
“Write a small program in TypeScript to adopt Shadow, this cat is lovely.”
The AI read both the OpenAPI and Arazzo specs, understood the workflow, and generated this:
async function main() { console.log("🐾 Starting Pet Adoption Workflow for Shadow\n");
// Step 1: Find Shadow const pets = await searchPets(); const shadow = pets.find( (pet) => pet.name.toLowerCase() === "shadow" && pet.status === "available" );
// Step 2: Background check with retry (it might fail! 😅 - the spec says it should stop but we retry for testing) let backgroundCheck: BackgroundCheckResponse; let attempts = 0; do { attempts++; backgroundCheck = await submitBackgroundCheck(ownerId); if (backgroundCheck.status === "rejected") { console.log(" Retrying background check..."); } } while (backgroundCheck.status === "rejected" && attempts < 10);
// Step 3: Training const training = await completeTraining(ownerId);
// Step 4: Adopt! const adoption = await adoptPet(shadow.id, ownerId);
console.log("🐾 Shadow has found a home! 🏠");}The AI added retry logic because it knew from the Arazzo spec that the background check could fail. It understood the workflow dependencies. It wired the pet ID from search to adoption.
This is what Arazzo enables.
The Shift for API Providers
Consider this new workflow:
- You ship OpenAPI specs (you probably already do)
- You add Arazzo workflows describing common use cases
- Your consumers point their AI assistant at both specs
- The AI generates working integration code, with proper error handling
No SDK maintenance. No outdated code samples. No “check the docs” support tickets. The AI reads your specs and writes correct client code in any language.
Instead of writing client libraries, you write specifications that let AI write client libraries.
Yes, you’re trading one maintenance burden (SDK code) for another (Arazzo specs). But specifications are lighter-weight, version alongside your API naturally, and work with any AI assistant rather than requiring language-specific SDK updates.
The Reality: An Emerging Ecosystem
Let’s be clear: Arazzo is new. The specification was released in May 2024, with version 1.0.1 in January 2025. The tooling ecosystem is still emerging. Tools exist for viewing and visualizing workflows, but there’s nothing yet for automatically generating client code from Arazzo specs. For now, you’ll be writing specs by hand and manually implementing the workflows they describe.
The maintenance burden is real. Every time your API evolves, you need to update both the OpenAPI spec AND the Arazzo workflows. You’ll need processes to keep them in sync, test them, and version them alongside your API.
But here’s the bet: as AI coding assistants become ubiquitous, having machine-readable workflow specifications becomes increasingly valuable. You’re investing early in a standard that makes your API not just documented, but executable.
Try It Yourself
I’ve published the complete demo on GitHub: marmelab/arazzo.
You can run the API server and the (mostly generated) JS client:
# Terminal 1: Start the servercd server && npm install && npm start
# Terminal 2: Adopt Shadowcd client && npm install && node adopt-shadow.tsYou’ll see:
🐾 Starting Pet Adoption Workflow for Shadow
📋 Step 1: Searching for available pets...✅ Found Shadow! Pet ID: pet-3
📋 Step 2: Submitting background check... Attempt 1... Status: rejected Attempt 2... Status: approved✅ Background check approved!
📋 Step 3: Completing training...✅ Training completed!
📋 Step 4: Adopting Shadow...🎉 Congratulations! You have successfully adopted Shadow!
🐾 Workflow completed successfully! Shadow has found a home! 🏠The Future: AsyncAPI Support
The Arazzo specification is actively evolving. The upcoming 1.1.0 release focuses on one major feature: support for AsyncAPI.
This is significant because modern APIs increasingly combine HTTP endpoints with event-driven patterns—webhooks, WebSockets, message queues. A checkout workflow might call a REST endpoint, then wait for a webhook confirmation. A real-time dashboard might subscribe to a WebSocket stream after authenticating via HTTP.
With AsyncAPI support, Arazzo workflows will be able to span both synchronous and asynchronous operations:
# Future Arazzo 1.1.0 (speculative syntax)sourceDescriptions: - name: orderAPI url: ./openapi.yaml type: openapi - name: orderEvents url: ./asyncapi.yaml type: asyncapi
workflows: - workflowId: place-order steps: - stepId: submit-order operationId: orderAPI.createOrder - stepId: wait-for-confirmation operationId: orderEvents.onOrderConfirmed # Wait for async event before proceedingThis will make Arazzo a comprehensive solution for describing modern API ecosystems—not just HTTP, but the full spectrum of API interactions.
Conclusion
Arazzo solves a real problem: the gap between “here are my endpoints” and “here’s how to use them together.” It’s what API documentation should be but rarely is.
For API providers, the proposition is compelling: ship Arazzo workflows alongside your OpenAPI spec, and you enable AI-assisted integration for all your users. No more hand-holding through multi-step processes. No more SDK maintenance. Just specifications that machines can read and execute.
For developers consuming APIs, Arazzo means your AI assistant finally understands not just what an API can do, but how to do it correctly.
The OpenAPI Initiative has given us a new tool. It’s up to us to use it.
Shadow has a home now. And your API documentation could be next.
Authors
Full-stack web developer at marmelab, Guillaume was initially a Java guy. Fan of anime and video games, he can develop an AI that beats you every time.