Onderwijsregio APIGuideAPI ReferenceChangelog
Status

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

  1. You send a mutation request

    • POST /v2/...

    • Create, update, or delete

    • Optionally with an idempotencyKey and callbackUrl

  2. The request is validated and accepted

    • Schema validation happens immediately

    • If valid, the mutation is queued

    • You receive a response right away

  3. The mutation is queued and serialized

    • Each Airtable base has its own internal queue

    • Mutations are processed one at a time, in order

  4. Execution happens asynchronously

    • The engine executes the mutation

    • Rate limits are enforced centrally

    • Temporary failures are retried automatically

  5. You are notified of the result

    • Via a signed callback (if provided)

    • Or by observing your own system state

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 (completed or failed)

  • 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.

Callback Signatures

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 idempotencyKey for safety

  • Use callbacks for completion

  • 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.