> ## Documentation Index
> Fetch the complete documentation index at: https://docs.serializedaudit.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit a Contract

> The single endpoint: send a contract, get a verdict.

Audit any contract on a [supported chain](/supported-chains). Send a `GET` request with your API key in the `X-Auth-Key` header; the full parameter and response reference is below.

By default the call is synchronous: it returns the cached verdict in milliseconds, or holds until a first-time audit completes. Add `async=true` to make first-time audits non-blocking: a cached verdict is still returned directly, but when an audit has to run you get `{ "status": "FETCHING" | "DECOMPILING" | "ANALYZING" }` immediately instead. Poll the same URL every 1-2 seconds until it flips to `{ "audit": ... }`, useful to drive a progress indicator. Billing is identical in both modes; progress responses are free.

Or skip polling entirely: add `subscribe=true` to fire the audit, subscribe the token, and have the finished verdict (plus every later change) **pushed to you** over a live SSE stream or a webhook. See [SSE & Webhooks](/sse-and-webhooks).

For how to read the result, see [Understanding Results](/understanding-results). For the full list of `type` values, see [Risk Categories](/risk-categories).


## OpenAPI

````yaml GET /audit-contract
openapi: 3.1.0
info:
  title: Serialized Audit API
  version: 1.0.0
  description: Submit a contract address and chain, receive an instant risk verdict.
servers:
  - url: https://www.serializedaudit.io/api
security:
  - apiKey: []
paths:
  /audit-contract:
    get:
      summary: Audit a contract
      description: >-
        Returns a safety verdict, a human-readable summary, identity, and the
        detected risks for the given contract. Results are returned in
        milliseconds when the contract has been audited before; a first-time
        audit may take a few seconds.
      operationId: auditContract
      parameters:
        - name: chain
          in: query
          required: true
          description: >-
            Chain the contract is deployed on, as a case-insensitive symbol. See
            Supported Chains.
          schema:
            type: string
            enum:
              - ETH
              - OP
              - ARB
              - BASE
              - BSC
              - AVAX
              - APE
              - BLAST
              - LINEA
              - MANTLE
              - POLYGON
              - ZKEVM
              - SCROLL
              - SONIC
              - ZKSYNC
              - ABSTRACT
              - MONAD
              - PLASMA
              - MEGAETH
              - HYPE
              - ROBINHOOD
              - ARC
              - STABLE
          example: base
        - name: address
          in: query
          required: true
          description: The contract address to audit.
          schema:
            type: string
            pattern: ^0x[a-fA-F0-9]{40}$
          example: '0x6D7401F6f1fB09ff24a048337ff44D890CdF86F8'
        - name: allow_decompile
          in: query
          required: false
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
            default: 'true'
          description: >-
            Closed-source contracts are audited on decompiled bytecode (the most
            expensive tier). Set false to opt out: closed-source contracts then
            answer `{ "audit": null, "reason": "decompile_disabled" }` instead
            of being decompiled, and cached decompiled verdicts are not served.
            Sent as the string "true"/"false" in the query.
        - name: async
          in: query
          required: false
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
            default: 'false'
          description: >-
            Async mode. `false` (default): the request holds until the audit is
            done, classic synchronous behavior. `true`: if no cached audit
            exists, the audit is started in the background and the response is
            `{ status }`; poll the SAME URL every 1-2s until it flips to `{
            audit }` (typically 10-30s for a first-time audit). There is no job
            id: an audit is idempotent per (chain, address), so the token
            address is the job handle. Billing is identical in both modes;
            progress responses are never billed. With `subscribe=true` you do
            not even poll: the finished verdict is pushed to you (over your SSE
            stream or webhook) the moment it lands (see SSE & Webhooks).
        - name: subscribe
          in: query
          required: false
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
            default: 'false'
          description: >-
            Subscribe this (chain, address) to push updates as part of this
            call. Once subscribed, any later verdict change (safe↔unsafe flip,
            owner change, a gate or honeypot flipping, or a closed-source token
            re-audited on its now-verified source) is pushed to you over a live
            SSE stream or a webhook, instead of you polling. Combined with
            `async=true`, the finished audit result is itself pushed when ready,
            so you fire the call and just consume the events. Subscribing works
            with or without a delivery transport configured; with neither, pull
            the changes from `GET /api/events` (see SSE & Webhooks). Charges the
            one-time subscribe fee for a genuinely-new token; idempotent for an
            already-subscribed one.
      responses:
        '200':
          description: The audit verdict, wrapped in an `audit` object.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/AuditResponse'
                  - $ref: '#/components/schemas/CachedMissResponse'
                  - type: object
                    description: >-
                      Only with `async=true`: the audit is still running. Poll
                      the same URL until the response carries `audit`. Steps may
                      be skipped (e.g. verified-source contracts never
                      decompile) and there is no terminal status; completion IS
                      the next poll returning `{ audit }`.
                    properties:
                      status:
                        type: string
                        enum:
                          - FETCHING
                          - DECOMPILING
                          - ANALYZING
                        description: >-
                          Current pipeline step: FETCHING (source code /
                          on-chain metadata), DECOMPILING (closed-source
                          contracts only), ANALYZING (LLM audit in progress).
                    required:
                      - status
              examples:
                safe:
                  summary: Safe contract
                  value:
                    audit:
                      isSafe: true
                      isTokenSafe: true
                      isHookSafe: null
                      description: >-
                        Standard ERC-20 token. No owner privileges that can harm
                        holders were detected.
                      vulnerabilities: []
                      name: Example Token
                      symbol: EXMPL
                      address: '0x6D7401F6f1fB09ff24a048337ff44D890CdF86F8'
                      chain: BASE
                      sourceType: verified
                      isProxy: false
                      implementationAddress: null
                      hookAddress: null
                      hookAudit: null
                      createdAt: '2026-06-22T10:00:00.000Z'
                      auditSystemVersion: prod-v2.10
                      latestAuditSystemVersion: prod-v2.10
                unsafe:
                  summary: Unsafe contract
                  value:
                    audit:
                      isSafe: false
                      isTokenSafe: false
                      isHookSafe: null
                      description: >-
                        The owner can mint unlimited supply after deployment,
                        diluting holders at will.
                      vulnerabilities:
                        - type: UnlimitedMinting
                          impact: critical
                          description: The owner can mint new tokens without limit.
                          code: >-
                            function mint(address to, uint256 amount) external
                            onlyOwner { _mint(to, amount); }
                          mitigated: false
                          gateReason: Owner is an active externally-owned account
                      name: Risky Token
                      symbol: RISK
                      address: '0x1111111111111111111111111111111111111111'
                      chain: BASE
                      sourceType: verified
                      isProxy: false
                      implementationAddress: null
                      hookAddress: null
                      hookAudit: null
                      createdAt: '2026-06-22T10:00:00.000Z'
                      auditSystemVersion: prod-v2.10
                      latestAuditSystemVersion: prod-v2.10
                inProgress:
                  summary: async=true, audit in progress, keep polling
                  value:
                    status: ANALYZING
        '400':
          description: Invalid request (e.g. unknown chain or malformed address).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: No active subscription, or your credit allowance is exhausted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentError'
        '404':
          description: >-
            The contract is not tradable yet (no liquidity pool found). Only
            tradable contracts are audited; retry once a pool exists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoPoolResponse'
              example:
                audit: null
                reason: no_liquidity_pool
                message: >-
                  No liquidity pool found for this token yet — only tradable
                  contracts are audited. Retry once a pool has been created.
        '429':
          description: >-
            Monthly spend cap reached (metered/enterprise accounts). Body
            carries cap_usd and used_usd; no action field.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    AuditResponse:
      type: object
      required:
        - audit
      description: The response shape.
      properties:
        audit:
          $ref: '#/components/schemas/Audit'
        billing:
          type: object
          description: >-
            Echo of what this call was billed, present only for authenticated
            API-key callers (never for anonymous/browser traffic). `type` is the
            bill category (e.g. cached, fresh_no_decompile,
            fresh_with_decompile, refresh) or null when the call is free;
            `credits` is the amount metered.
          properties:
            type:
              type:
                - string
                - 'null'
            credits:
              type: number
          required:
            - type
            - credits
    CachedMissResponse:
      type: object
      required:
        - audit
        - reason
        - message
      description: >-
        HTTP 200 miss body (non-billed). Returned when allow_decompile=false and
        the only path to a verdict would be decompilation (reason
        decompile_disabled): no verdict is produced. Retry with
        allow_decompile=true (the default) to get a full audit.
      properties:
        audit:
          type: 'null'
          description: Always null; no verdict is served for this miss.
        reason:
          type: string
          enum:
            - decompile_disabled
          description: Machine-readable reason for the miss.
        message:
          type: string
          description: Human-readable explanation.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
    PaymentError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        action:
          type: string
          description: Suggested next step.
          enum:
            - wait
            - subscribe
            - add_payment
            - resubscribe
            - verify_payment
            - payment_processing
            - raise_cap
            - upgrade
      description: >-
        Billing denial. Bodies may carry additional context fields depending on
        the wall (resets_at, daily_limit, grace_usd, current_period_end,
        subscription_status).
    NoPoolResponse:
      type: object
      required:
        - audit
        - reason
      properties:
        audit:
          type: 'null'
          description: Always null; no audit is produced for a non-tradable contract.
        reason:
          type: string
          enum:
            - no_liquidity_pool
          description: Machine-readable reason.
        message:
          type: string
          description: Human-readable explanation.
    Audit:
      type: object
      required:
        - isSafe
        - description
        - address
        - chain
        - vulnerabilities
      description: The audit result.
      properties:
        isSafe:
          type: boolean
          description: >-
            The overall verdict, your decision boundary. true means no
            holder-harming risk was active at audit time. Combines the token
            verdict and, if present, the hook verdict.
        isTokenSafe:
          type: boolean
          description: >-
            Verdict for the token contract itself, ignoring any associated pool
            hook.
        isHookSafe:
          type:
            - boolean
            - 'null'
          description: >-
            Verdict for the associated Uniswap v4 pool hook, or null when the
            token has no hook.
        description:
          type: string
          description: >-
            A short, human-readable explanation of the verdict, safe to show in
            a UI.
        vulnerabilities:
          type: array
          description: The detected risks. Empty when the contract is safe.
          items:
            $ref: '#/components/schemas/Vulnerability'
        name:
          type:
            - string
            - 'null'
          description: Token name, when available.
        symbol:
          type:
            - string
            - 'null'
          description: Token symbol, when available.
        address:
          type: string
          description: The audited contract address (echoed back).
        chain:
          type: string
          description: The chain symbol (echoed back).
        sourceType:
          type: string
          enum:
            - verified
            - decompiled
            - b20
            - none
          description: >-
            How the analyzed code was obtained: verified (published source),
            decompiled (reconstructed from bytecode), b20 (a Base native B20
            token with no bytecode; the verdict is read deterministically from
            on-chain flags), or none.
        isProxy:
          type: boolean
          description: >-
            Whether the contract is a proxy. When true, the verdict already
            reflects its implementation.
        implementationAddress:
          type:
            - string
            - 'null'
          description: >-
            For a proxy, the implementation contract that was audited; null
            otherwise.
        hookAddress:
          type:
            - string
            - 'null'
          description: Address of the associated Uniswap v4 pool hook, when present.
        hookAudit:
          oneOf:
            - $ref: '#/components/schemas/HookAudit'
            - type: 'null'
          description: >-
            The audit of the associated pool hook, or null when there is no
            hook.
        createdAt:
          type: string
          format: date-time
          description: ISO timestamp of when this audit was produced.
        auditSystemVersion:
          type: string
          description: >-
            The version of the audit system that produced this result. Useful to
            gate on newly added fields.
        latestAuditSystemVersion:
          type: string
          description: >-
            The latest audit system version. If it differs from
            auditSystemVersion, the result refreshes to the latest on the next
            visit.
        b20Flags:
          type:
            - object
            - 'null'
          description: >-
            Live on-chain flag snapshot for a Base-native B20 token. null on
            every other sourceType.
          properties:
            is_b20:
              type: boolean
              description: Always true on a B20 row.
            initialized:
              type: boolean
            variant:
              type:
                - string
                - 'null'
              enum:
                - asset
                - stablecoin
                - null
              description: B20 variant, or null if unknown.
            paused_features:
              type: array
              items:
                type: integer
              description: >-
                PausableFeature enum values currently paused: 0=TRANSFER,
                1=MINT, 2=BURN.
            policy_sender:
              type: string
              description: >-
                Transfer-policy id (uint64 decimal string). '0' = ALWAYS_ALLOW
                (open).
            policy_receiver:
              type: string
              description: As policy_sender, receiver scope.
            policy_executor:
              type: string
              description: As policy_sender, executor scope.
            policy_mint:
              type: string
              description: As policy_sender, mint scope.
            multiplier:
              type:
                - string
                - 'null'
              description: >-
                Rebase multiplier (asset variant), WAD decimal string; 1e18 =
                neutral. null when absent/unreadable.
            supply_cap:
              type:
                - string
                - 'null'
              description: >-
                uint256 decimal string; type(uint128).max = uncapped.
                Informational.
    Vulnerability:
      type: object
      required:
        - type
        - impact
        - description
      properties:
        type:
          type: string
          description: >-
            Risk category. See Risk Categories for the full list. Treat as an
            open set and handle unknown values gracefully.
          examples:
            - UnlimitedMinting
            - HiddenFees
            - LiquidityDrain
        impact:
          type: string
          enum:
            - critical
            - warning
            - info
          description: How severely this risk affects a holder.
        description:
          type: string
          description: Plain-language explanation of the risk.
        code:
          type: string
          description: A representative snippet of the relevant code for this risk.
        codes:
          type: array
          items:
            type: string
          description: >-
            All relevant snippets when several functions share this risk. `code`
            is the first of them. Present only when more than one applies.
        mitigated:
          type:
            - boolean
            - 'null'
          description: >-
            Whether this specific risk is currently neutralized (e.g. the
            controlling owner has renounced). null when not applicable.
        gateReason:
          type:
            - string
            - 'null'
          description: >-
            Human-readable explanation of the current state, e.g. "Owner
            renounced" or "MINTER_ROLE has 2 active holders". Display-ready.
    HookAudit:
      type: object
      description: Audit of an associated Uniswap v4 pool hook.
      properties:
        isSafe:
          type:
            - boolean
            - 'null'
          description: Verdict for the hook.
        description:
          type:
            - string
            - 'null'
          description: Human-readable summary of the hook verdict.
        vulnerabilities:
          type: array
          items:
            $ref: '#/components/schemas/Vulnerability'
          description: Risks detected in the hook.
        address:
          type:
            - string
            - 'null'
          description: The hook contract address.
        isDecompiled:
          type: boolean
          description: >-
            Whether the hook verdict came from decompiled bytecode (no verified
            source).
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-Auth-Key
      description: Your secret API key. Create one from your dashboard.

````