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

# Payload format

> The JSON Tumban POSTs to your callback URL when a scan completes.

When a scan reaches a terminal status (`completed` or `failed`),
Tumban issues a `POST` to the scan's `callback_url` with a JSON body.
Headers:

* `Content-Type: application/json`
* `X-Tumban-Signature`, `X-Tumban-Signature-V2`, `X-Tumban-Timestamp`,
  `X-Tumban-Org-Id` — when the organization has a webhook secret. See
  [Signature verification](/webhooks/signatures) for the full header
  reference and verifier snippets.

## Body

<ResponseField name="scan_id" type="string" required>
  The scan id you received when submitting.
</ResponseField>

<ResponseField name="profile_url" type="string" required>
  The submitted profile URL.
</ResponseField>

<ResponseField name="status" type="string" required>
  `completed` or `failed`. See [Status values](/reference/status) for
  the full reference.
</ResponseField>

<ResponseField name="completed_at" type="string" required>
  ISO 8601 UTC timestamp.
</ResponseField>

<ResponseField name="recommendation" type="string" required>
  See [Recommendation values](/reference/recommendation). On a failed
  scan, Tumban defaults this to `review_high` so the profile lands in
  your queue for manual triage.
</ResponseField>

<ResponseField name="risk_score" type="integer" required>
  0–100. On a failed scan, defaults to `50`.
</ResponseField>

<ResponseField name="confidence" type="string" required>
  `low`, `medium`, or `high`. On a failed scan, defaults to `low`.
</ResponseField>

<ResponseField name="reason_codes" type="string[]" required>
  See [Reason codes](/reference/reason-codes). On a failed scan, this
  is `["SCAN_FAILED"]`.
</ResponseField>

<ResponseField name="reason_summary" type="string" required>
  Human-readable summary. On a failed scan, this contains the error
  message.
</ResponseField>

<ResponseField name="review_targets" type="string[]" required>
  URLs your reviewers should look at first. On a failed scan, this is
  `["manual_investigation_required"]`.
</ResponseField>

<ResponseField name="link_chain" type="string" required>
  Short label describing the path Tumban followed (e.g.
  `Profile -> External site`). Empty string on a failed scan.
</ResponseField>

<ResponseField name="coverage" type="object" required>
  Which analysis steps ran. See [Coverage](/concepts/coverage).
</ResponseField>

<ResponseField name="metadata" type="object" required>
  The metadata you submitted with the scan, echoed back unchanged.
  Always present: defaults to `{}` when the scan was submitted without a
  `metadata` body field.
</ResponseField>

<ResponseField name="evidence_index" type="object[]">
  Per-URL evidence Tumban cited in support of the decision. May be `[]`
  when Tumban reached its decision without a per-URL citation to
  surface. See [Evidence index](/concepts/evidence-index).
</ResponseField>

<ResponseField name="error" type="string">
  Present when `status` is `failed`. Brief description of what went
  wrong.
</ResponseField>

## Example — completed

```json theme={null}
{
  "scan_id": "550e8400-e29b-41d4-a716-446655440000",
  "profile_url": "https://creator.example/username",
  "status": "completed",
  "completed_at": "2026-04-29T12:01:38.987654+00:00",
  "recommendation": "review_high",
  "risk_score": 85,
  "confidence": "high",
  "reason_codes": ["PROHIBITED_DOMAIN", "ADULT_KEYWORDS"],
  "reason_summary": "Direct link to a prohibited platform combined with adult keywords in bio.",
  "review_targets": ["https://prohibited-platform.example/username"],
  "link_chain": "Profile -> External site",
  "coverage": {
    "profile_scraped": true,
    "external_search_completed": true,
    "social_links_checked": 3,
    "blocked_by_login": [],
    "referrer_domains_received": 12,
    "referrer_domains_after_filter": 4,
    "referrer_matches_found": 1
  },
  "metadata": {"reviewer_id": "rv_42"},
  "evidence_index": [
    {
      "ref": "link_1",
      "url": "https://prohibited-platform.example/username",
      "type": "traversed_link",
      "domain": "prohibited-platform.example"
    }
  ]
}
```

## Example — failed

```json theme={null}
{
  "scan_id": "550e8400-e29b-41d4-a716-446655440000",
  "profile_url": "https://creator.example/username",
  "status": "failed",
  "completed_at": "2026-04-29T12:01:38.987654+00:00",
  "recommendation": "review_high",
  "risk_score": 50,
  "confidence": "low",
  "reason_codes": ["SCAN_FAILED"],
  "reason_summary": "timeout_exceeded_450s",
  "review_targets": ["manual_investigation_required"],
  "link_chain": "",
  "coverage": {
    "profile_scraped": false,
    "external_search_completed": false,
    "social_links_checked": 0,
    "blocked_by_login": [],
    "referrer_domains_received": 0,
    "referrer_domains_after_filter": 0,
    "referrer_matches_found": 0
  },
  "metadata": {"reviewer_id": "rv_42"},
  "evidence_index": [],
  "error": "timeout_exceeded_450s"
}
```

## Acknowledging a webhook

Tumban considers a webhook delivered when your endpoint responds with a
`2xx` status. Other statuses are retried — see
[Delivery and retries](/webhooks/delivery).
