Skip to main content
This is the integration we recommend to every new client. It is the pattern our highest-volume production integrations run on. Three rules cover it:
  1. Fire-and-subscribe. The first time a token appears on your side, call /audit-contract with async=true&subscribe=true. The call returns immediately, and the finished audit is pushed to you.
  2. Hold one SSE stream open. Keep a single long-lived GET /api/stream connection. Every finished audit and every later verdict change arrives there as an audit.changed event carrying the complete audit object.
  3. Your cache follows the stream. Store what the stream sends, keyed by (chain, address). No TTL, no refresh calls, no staleness logic. The stream is the source of truth.

1. Fire the audit

Two possible responses:
  • { "audit": { ... } }: the token was already audited. Store it, you are done. The subscription is created either way.
  • { "status": "FETCHING" | "DECOMPILING" | "ANALYZING" }: a fresh audit is running. Do nothing. The finished verdict arrives on your stream.

2. Hold the stream

  • The stream carries events for the tokens you are subscribed to.
  • evt.audit is the complete new verdict, the exact same object /audit-contract returns. Storing it is the entire update.
  • Reconnection and resume are automatic (Last-Event-ID): after a disconnect you receive everything you missed, in order.
  • We send a keepalive comment every 25 seconds. Reconnect on any disconnect, with your own backoff.

That is the whole loop

What it gives you:
  • Every subscribed token is re-checked onchain continuously, and every verdict change is pushed: a safe/unsafe flip, an owner change or renounce, a gate or a honeypot turning on or off.
  • Re-audits we trigger are free, including closed-source tokens whose source verifies later: you receive the verified verdict automatically.
  • Your users always see the current verdict. There is no stale-data window.
  • Your credit spend drops: a subscription is 2 credits once per token, instead of refresh calls forever. See Credits & Billing.

What NOT to build

  • No polling loop. Do not re-call /audit-contract to keep a verdict fresh. Changes come to you.
  • No cache TTL. A stored verdict stays valid until an audit.changed event replaces it.
  • No re-fetch on push. The event already contains the full audit. Do not call the API back.
  • No status polling. With async=true&subscribe=true the result is pushed. Polling still works, it is just never needed.

Alternatives, when they fit better

  • Synchronous + subscribe: call /audit-contract with only subscribe=true and get the audit directly in the response (the call stays open while a fresh audit runs). The stream still handles all future changes.
  • Webhooks instead of SSE: we POST each event, HMAC-signed, to your HTTPS endpoint. Same payloads, same guarantees. See SSE & Webhooks.
  • Catch-up replay: GET /api/events?since=<last_id> returns anything you missed. It is the durable backstop behind both transports.
For LLMs and coding agents: the full documentation is one markdown file at https://docs.serializedaudit.io/llms-full.txt.