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

# Force refresh of legal corpus rows

> Triggers an out-of-band refresh of one or more rows in your tenant's legal corpus.
Each corpus row is the pre-researched legal context that Stage A consumes — refreshing
replaces its enrichment with the latest available regulator guidance.

**When you'd use this**: regulatory guidance changed mid-window, or you want fresh
enrichment before running an important compliance check.

**Idempotent**: concurrent calls or repeated calls on the same row don't fan out
duplicate work — calls that arrive while a refresh is already in flight return
`skippedCount += 1` instead of enqueueing.

**Rate-limited**: max 50 rows enqueued per call. Excess returns as `pending`.
Re-call after ~1 minute to drain remaining rows.

**Async**: returns immediately after enqueueing; the actual refresh runs on a
background worker. Subsequent reads automatically pick up the new enrichment.




## OpenAPI

````yaml /openapi/zebratruth-v1.yaml post /corpus/refresh
openapi: 3.1.0
info:
  title: ZebraTruth Compliance API
  version: 1.0.0
  description: >
    AI-powered compliance checking for advertising content. Check text and
    images against

    jurisdiction laws, platform policies, and rights clearance requirements.
    Results include

    embeddable annotations mapped to content locations (text spans, video
    timestamps, image regions).
  contact:
    name: ZebraTruth Support
    email: support@zebratruth.ai
    url: https://developers.zebratruth.ai
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
  - url: https://api.zebratruth.ai/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Video Compliance
    description: >
      **Primary endpoint.** Async compliance analysis for video ads. 3-step
      flow:

      get an upload URL, upload the video bytes, submit for analysis. Poll or

      receive an HMAC-signed webhook with the report. Returns timestamped

      findings citing stable evidence IDs (`audio_NNN`, `frame_NNN`, `ocr_NNN`,

      `signal_NNN`). 3-180 second videos. mp4 / webm /

      quicktime. Built for ad agencies and creators.
  - name: Authentication
    description: Validate API keys and check account status
  - name: Compliance
    description: >-
      Run compliance checks on text + image content (sync). For video, use the
      Video Compliance endpoints above.
  - name: Agents
    description: Discover and invoke individual compliance agents
  - name: Jobs
    description: Poll async job status and view execution traces
  - name: Reports
    description: Retrieve and replay compliance reports
  - name: Observability
    description: Request logs and webhook delivery status
  - name: Billing
    description: Subscriptions, plan changes, and credit balance
  - name: Documents
    description: Extract text from PDF and Word documents before or as part of a check
  - name: Check History
    description: List and retrieve past compliance checks for the workspace
  - name: Provenance
    description: Inspect and sign Content Credentials (C2PA) on images and video
  - name: Corpus
    description: >-
      Review queue for proposed changes to the governed legal corpus (dashboard
      session)
  - name: Webhooks
    description: Saved webhook endpoints (dashboard session) and delivery logs
paths:
  /corpus/refresh:
    post:
      tags:
        - Compliance
      summary: Force refresh of legal corpus rows
      description: >
        Triggers an out-of-band refresh of one or more rows in your tenant's
        legal corpus.

        Each corpus row is the pre-researched legal context that Stage A
        consumes — refreshing

        replaces its enrichment with the latest available regulator guidance.


        **When you'd use this**: regulatory guidance changed mid-window, or you
        want fresh

        enrichment before running an important compliance check.


        **Idempotent**: concurrent calls or repeated calls on the same row don't
        fan out

        duplicate work — calls that arrive while a refresh is already in flight
        return

        `skippedCount += 1` instead of enqueueing.


        **Rate-limited**: max 50 rows enqueued per call. Excess returns as
        `pending`.

        Re-call after ~1 minute to drain remaining rows.


        **Async**: returns immediately after enqueueing; the actual refresh runs
        on a

        background worker. Subsequent reads automatically pick up the new
        enrichment.
      operationId: refreshCorpus
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CorpusRefreshRequest'
      responses:
        '200':
          description: Refresh enqueued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CorpusRefreshResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantScopeDenied'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  schemas:
    CorpusRefreshRequest:
      oneOf:
        - type: object
          title: All stale rows
          required:
            - scope
          properties:
            scope:
              type: string
              enum:
                - all
              description: Refresh every stale row in the tenant's corpus.
        - type: object
          title: Area-scoped
          required:
            - scope
            - area
            - jurisdictions
          properties:
            scope:
              type: string
              enum:
                - area
            area:
              type: string
              enum:
                - ai_content
                - advertising
                - metadata
                - rights
                - data_privacy
                - platform_policy
              description: Which corpus area to refresh.
            jurisdictions:
              type: array
              items:
                type: string
                enum:
                  - us
                  - eu
                  - uk
                  - india
                  - china
              minItems: 1
              description: Which jurisdictions in scope.
        - type: object
          title: Single law
          required:
            - scope
            - area
            - jurisdiction
            - lawId
          properties:
            scope:
              type: string
              enum:
                - law
            area:
              type: string
              enum:
                - ai_content
                - advertising
                - metadata
                - rights
                - data_privacy
                - platform_policy
            jurisdiction:
              type: string
              enum:
                - us
                - eu
                - uk
                - india
                - china
            lawId:
              type: string
              description: Specific law id from `jurisdiction-laws.ts`.
              example: ftc-ai-impersonation-rule
      description: |
        Discriminated union on `scope`. Pick the narrowest scope you need —
        `all` for everything stale, `area` to limit by jurisdiction × area,
        or `law` for a single row.
    CorpusRefreshResponse:
      type: object
      required:
        - requestedCount
        - enqueuedCount
        - skippedCount
        - pending
        - rateLimit
      properties:
        requestedCount:
          type: integer
          description: How many corpus rows the requested scope resolved to.
          example: 12
        enqueuedCount:
          type: integer
          description: >-
            How many rows successfully acquired the lease + got a refresh
            message enqueued.
          example: 9
        skippedCount:
          type: integer
          description: |
            Rows where the lease is currently held by another recent caller
            (5-min window) or whose row didn't exist. These will refresh on
            the existing lease holder's enqueue.
          example: 3
        pending:
          type: integer
          description: |
            Rows over the 50/request rate limit. Re-call after ~1 minute to
            enqueue the rest.
          example: 0
        rateLimit:
          type: integer
          description: Maximum rows enqueued per request.
          example: 50
  responses:
    Unauthorized:
      description: |
        Invalid, missing, or expired API key. Standard error envelope —
        read `message` for the human-readable reason.
      content:
        application/json:
          schema:
            type: object
            description: Standard error envelope.
            required:
              - statusCode
              - message
            properties:
              error:
                type: boolean
                example: true
              url:
                type: string
                format: uri
                example: https://api.zebratruth.ai/v1/whoami
              statusCode:
                type: integer
                example: 401
              statusMessage:
                type: string
                example: Invalid API key
              message:
                type: string
                description: Canonical human-readable reason — pattern-match on this field.
                example: Invalid API key
    TenantScopeDenied:
      description: >
        The request asks for a jurisdiction or platform not in your
        subscription, or your

        tenant record is missing / incomplete. The human-readable reason is in
        the

        `statusMessage` and `message` fields (both carry the same string —
        `message` is

        the canonical field in the error envelope). Five possible messages:


        - **Not onboarded** — no tenant record exists yet.
          `"Tenant not onboarded. Complete setup at https://developers.zebratruth.ai before using the API."`
        - **Incomplete config** — tenant exists but has no default jurisdictions
        or platforms set.
          `"Tenant configuration incomplete. Set default jurisdictions and platforms in your dev portal."`
        - **Jurisdiction not subscribed** — request includes jurisdictions
        outside the subscription.
          `"Requested jurisdictions [india, china] are not in your subscription. Allowed: [us, eu]."`
        - **Platform not subscribed** — request includes platforms outside the
        subscription.
          `"Requested platforms [tiktok] are not in your subscription. Allowed: [youtube, instagram]."`
        - **Scope wider than the plan allows** — carries `data.code:
          "scope_limit_exceeded_config"`, the only one of the five that does.
          `"Your plan allows at most 2 jurisdictions, but your account has 3 selected. Reduce your
          jurisdictions in the developer portal, or request at most 2 on this call."`
          Reachable after a plan change, because a scope chosen during the unlimited trial can be
          wider than the plan you end up on.

        Fix: either adjust the request to stay within the subscribed set, or
        update your

        defaults at `https://developers.zebratruth.ai/dashboard/settings`.
      content:
        application/json:
          schema:
            type: object
            description: >-
              Standard error envelope. Read `message` (or `statusMessage`) for
              the human-readable reason.
            required:
              - statusCode
              - message
            properties:
              error:
                type: boolean
                description: Always `true` for error responses.
                example: true
              url:
                type: string
                format: uri
                description: The URL that was requested.
                example: https://api.zebratruth.ai/v1/compliance/check
              statusCode:
                type: integer
                example: 403
              statusMessage:
                type: string
                description: Human-readable reason — same content as `message`.
                example: >-
                  Requested jurisdictions [india, china] are not in your
                  subscription. Allowed: [us, eu].
              message:
                type: string
                description: >-
                  Canonical human-readable reason — pattern-match on this field
                  in client code.
                example: >-
                  Requested jurisdictions [india, china] are not in your
                  subscription. Allowed: [us, eu].
    RateLimited:
      description: |
        Per-tenant rate limit exceeded. Read the `Retry-After` header for the
        wait duration. Body is the standard error envelope plus a
        `data` object with limit context.
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying.
      content:
        application/json:
          schema:
            type: object
            description: Standard error envelope with a `data` payload.
            required:
              - statusCode
              - message
            properties:
              error:
                type: boolean
                example: true
              url:
                type: string
                format: uri
              statusCode:
                type: integer
                example: 429
              statusMessage:
                type: string
                example: Rate limit exceeded
              message:
                type: string
                example: Rate limit exceeded
              data:
                type: object
                description: >-
                  Per-error context. On the wire this is reduced to `{ code }`
                  plus, where documented, a small set of named fields.
                properties:
                  retryAfter:
                    type: integer
                    description: >-
                      Mirrors the `Retry-After` header for clients that prefer
                      body fields.
                    example: 5
                  limit:
                    type: integer
                    description: Tenant's requests-per-minute cap.
                    example: 60
                  remaining:
                    type: integer
                    description: Requests remaining in the current window.
                    example: 0
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        API key starting with `zt_live_` (production) or `zt_test_` (sandbox).
        Get your key at https://developers.zebratruth.ai

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.