Cereal docs
TypeScript SDK

Callback verification

Automatically verify agent callbacks, or build a standalone verifier for a custom route.

agent.handlers and agent.fetch verify callbacks before dispatching tools or hooks. Each app process learns the organization and environment from its Cereal API key. This works without an earlier sync in that process. The configured application origin and route paths determine the expected audience.

Checks cover the signature, token lifetime, body integrity, audience, replay and organization/environment/agent/connection identity. For application tools, prefer these handlers and the framework adapters.

Standalone routes

Use @trycereal/sdk/verify for custom middleware or callback routes outside a defined agent. Learn tenant context from the credential, then hold one verifier so its key cache can be reused:

import { getCerealClient } from "@trycereal/sdk"
import { createCerealVerifier, CerealSignatureError } from "@trycereal/sdk/verify"

const context = await getCerealClient().me()
const verify = createCerealVerifier({
  audience: "https://app.example.com/custom-hook",
  purpose: "hook",
  expect: {
    org: context.organization.slug,
    env: context.environment.slug,
    agent: "support",
    connection: "support"
  }
})

export async function POST(request: Request) {
  try {
    const verified = await verify(request)
    // Dispatch your callback using verified.body and verified.session.
    return Response.json({ ok: true })
  } catch (error) {
    if (error instanceof CerealSignatureError)
      return Response.json({ reason: error.reason }, { status: 401 })
    throw error
  }
}

The audience must match the callback URL registered with Cereal. Agent and connection expectations identify the resources this custom endpoint serves. Never derive expected tenancy from an unverified incoming token. The verifier selects the organization's published key set from trusted configuration and asserts the signed claims.

verifyCerealRequest is the one-shot alternative. createCerealVerifier reuses its key cache across requests. Both preserve the original request body for the caller. The default replay store is per process; use a shared store when replicas must share replay detection. See verification options.

FailureMeaning
missing_tokenNo credential in the expected header
invalid_signature / unknown_keySignature or signing key could not be verified
expiredToken lifetime has ended
audience_mismatchThe token targets another endpoint
body_hash_mismatchRequest bytes differ from the signed body
purpose_mismatchA tool signature arrived at a hook endpoint, or vice versa
tenant_mismatch / agent_mismatch / connection_mismatchThe signed resource identity does not match the endpoint
replayedThe token was already accepted by the replay store

Signed claims · CerealSignatureError

On this page