Mutation Engine
The Mutation Engine is the system responsible for all write operations in our API.
Any request that creates, updates, or deletes data is handled by the Mutation Engine. Instead of executing mutations immediately, requests are queued, validated, serialized, and processed asynchronously.
This is not an implementation detail — it is a core design choice that guarantees consistency, reliability, and predictable behavior under load.
Why the Mutation Engine exists
Directly writing to Airtable from a public API introduces hard problems:
-
Strict rate limits
-
Eventual consistency
-
Transient failures
-
Ordering issues
-
Retry storms
-
Client-side duplication and race conditions
Exposing those constraints directly to API consumers would make the API fragile and difficult to use. The Mutation Engine exists to absorb that complexity so clients don’t have to.
Our goals are simple:
-
Mutations are executed in the correct order
-
Temporary failures are retried automatically
-
Rate limits are respected centrally
-
Clients get clear, consistent outcomes
-
No mutation is lost or executed twice unintentionally
The Mutation Lifecycle
-
You send a mutation request
-
POST /v2/... -
Create, update, or delete
-
Optionally with an
idempotencyKeyandcallbackUrl
-
-
The request is validated and accepted
-
Schema validation happens immediately
-
If valid, the mutation is queued
-
You receive a response right away
-
-
The mutation is queued and serialized
-
Each Airtable base has its own internal queue
-
Mutations are processed one at a time, in order
-
-
Execution happens asynchronously
-
The engine executes the mutation
-
Rate limits are enforced centrally
-
Temporary failures are retried automatically
-
-
You are notified of the result
-
Via a signed callback (if provided)
-
Or by observing your own system state
-
Mutation Engine Responses
Upon requesting a mutation, you can receive either a success response or a failure response. Below are examples of the different response types:
{
"statusCode": 202,
"message": "The Mutation Engine has accepted the request for processing",
"data": {
"mutationId": "71823522-1bfb-49b8-885f-ceea9d782ad2",
"status": "queued"
}
}
Note that a validation error coming from the Mutation Engine does not mean you have provided an invalid payload.
Payload validation happens before sending the request mutation to the mutation engine, so this is a validation error in the internal contract.
In practice, you should never encounter this error.
{
"error": true,
"url": "https://onderwijsregio.onderwijsin.nl/api/v2/candidates",
"statusCode": 500,
"statusMessage": "Server Error",
"message": "Mutation engine rejected the mutation request due to validation errors",
"data": {
"idempotencyKey": "your-key",
"issues": [
... List of Zod validation issues ...
]
}
}
{
"error": true,
"url": "https://onderwijsregio.onderwijsin.nl/api/v2/candidates",
"statusCode": 500,
"statusMessage": "Server Error",
"message": "Unknown error from mutation engine",
"data": {
"idempotencyKey": "your-key"
}
}
{
"error": true,
"url": "https://onderwijsregio.onderwijsin.nl/api/v2/candidates",
"statusCode": 500,
"statusMessage": "Server Error",
"message": "Mutation engine declined the mutation request: {message}",
"data": {
"idempotencyKey": "your-key"
}
}
{
"statusCode": 202,
"message": "The Mutation Engine has accepted the request for processing",
"data": {
"mutationId": "71823522-1bfb-49b8-885f-ceea9d782ad2",
"status": "idempotency_hit",
"idempotencyKey": "your-idempotency-key",
}
}
Idempotent Operations
You may provide an idempotencyKey with mutation requests.
If the same key is sent multiple times:
-
The mutation is only executed once
-
Duplicate requests return the same
mutationId
This is strongly recommended for:
-
Network retries
-
Client restarts
-
Exactly-once semantics
Callback URLs
Because mutations are asynchronous, the recommended way to observe completion is via callbacks.
If you provide a callbackUrl:
-
We will POST the result once processing finishes
-
Callbacks are signed and retry-safe
-
Failures are retried independently
Callback payloads include:
-
mutationId -
idempotencyKey(if provided) -
Final status (
completedorfailed) -
Result or error details
{
mutationId: '<uuid of operation>',
idempotencyKey: '<your provided idempotency key>',
status: 'completed',
result: { /* operation-specific result */ }
}
{
mutationId: '<uuid of operation>',
idempotencyKey: '<your provided idempotency key>',
status: 'failed',
result: {
errorCode: '<errorCode>',
status: '<http status code, if applicable>',
message: '<error message>',
attempts: '<number of attempts made>',
}
}
It is important that your callback endpoint rejects requests from untrusted sources. You should verify the signature included with each callback to ensure it originated from the Mutation Engine.
Learn how to verify that requests to your callback endpoint are made from the mutation engine.
Designing Your Integration
When integrating with the Mutation Engine, you should:
-
Treat mutation responses as acknowledgements, not results
-
Use
idempotencyKeyfor safety -
Use callbacks for completion or to log errors to your monitoring tools.
-
Design your system to be event-driven, not synchronous
-
Assume mutations may take seconds, not milliseconds
This model leads to simpler, safer, and more resilient systems.