Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ Use `loc` to locate the field — the last segment is the field name.
| 401 | `Invalid or revoked API key` | The `sk_…` token is unknown or revoked. |
| 403 | `Token missing org_id — make sure you have an active organization selected` | Dashboard session has no active org. |
| 403 | `API key management requires a dashboard session. API keys cannot revoke API keys.` | [Revoke API key](/api/keys/revoke) when called with `sk_…` auth. |
| 403 | `This endpoint requires a dashboard session. API keys are not permitted.` | [Create API key](/api/keys/create), [List API keys](/api/keys/list) when called with `sk_…` auth. |
| 403 | `Admin role required` | [Update org settings](/api/org/update-settings), [Rotate webhook secret](/api/webhook-secret/rotate) when the caller is a non-admin. |
| 403 | `This endpoint requires an admin dashboard session. API keys cannot access admin endpoints.` | [Update org settings](/api/org/update-settings), [Rotate webhook secret](/api/webhook-secret/rotate) when called with `sk_…` auth. |
| 422 | `Invalid callback URL: <reason>` | [Update org settings](/api/org/update-settings) when `default_callback_url` resolves to a private/internal address. |
| 404 | `Scan not found` | [Get scan](/api/scans/get). |
| 404 | `Batch not found` | [Get batch](/api/scans/batch-get). |
| 404 | `Org settings not found` | Org settings or usage endpoints. |
| 404 | `Org settings not found` | Org settings endpoints. |
| 404 | `API key not found or already revoked` | [Revoke API key](/api/keys/revoke). |
| 400 | `No fields to update` | [Update org settings](/api/org/update-settings). |
| 400 | `Invalid recommendation values: [...]` | [List org scans](/api/org/list-scans). |
Expand Down
5 changes: 2 additions & 3 deletions api/scans/batch-get.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ GET /api/v2/batches/{batch_id}
</ResponseField>

<ResponseField name="completed" type="integer" required>
Count of profiles whose scans completed successfully. The reserved
`completed_with_partial` status is rolled into this count when it
starts firing — see [Status values](/reference/status).
Count of profiles whose scans completed successfully. See
[Status values](/reference/status).
</ResponseField>

<ResponseField name="failed" type="integer" required>
Expand Down
20 changes: 13 additions & 7 deletions api/scans/batch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,23 +134,29 @@ response = httpx.post(

When the org's `daily_scan_limit` has capacity for fewer profiles than
were requested, the batch is accepted with the leading N profiles only
and the response sets `daily_limit_truncated` and `profiles_skipped`:
and the response sets `daily_limit_truncated` and `profiles_skipped`.

**Worked example.** Submit 50 URLs with 30 remaining in the daily
quota → the **first 30** URLs (in submission order) are queued; the
**last 20** are dropped:

```json
{
"batch_id": "9b8a7c6d-1234-5678-9abc-def012345678",
"status": "processing",
"total_profiles": 2,
"total_profiles": 30,
"submitted_at": "2026-04-29T12:00:00.123456+00:00",
"estimated_completion": "2026-04-29T12:04:00.123456+00:00",
"estimated_completion": "2026-04-29T13:00:00.123456+00:00",
"daily_limit_truncated": true,
"profiles_skipped": 1
"profiles_skipped": 20
}
```

The remaining profile URLs (the last `profiles_skipped` entries from the
request, in order) were not queued. Resubmit them after the next daily
window opens at `00:00 UTC`.
`total_profiles` is the count actually queued (30), not the count
submitted (50). To recover the skipped URLs, take the last
`profiles_skipped` entries from your original `profile_urls` array — in
the same order — and resubmit them after the next daily window opens at
`00:00 UTC`.

## Errors

Expand Down
47 changes: 19 additions & 28 deletions api/scans/get.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ The response is the scan record. Fields you should rely on:
When pipeline processing finished. `null` while still processing.
</ResponseField>

<ResponseField name="is_banned" type="boolean | null">
`null` until the ban-checker has evaluated this profile, then `true`
if the creator has been banned by the upstream platform (e.g. 404 /
410 / redirect on the profile URL) or `false` if the profile is
still live. Useful for skipping enforcement on already-banned
creators.
</ResponseField>

<ResponseField name="callback_url" type="string">
The callback URL the scan was submitted with (or the org default if
not provided), as a string. Empty when no callback was configured.
Expand All @@ -78,9 +86,8 @@ The response is the scan record. Fields you should rely on:
</ResponseField>

<ResponseField name="triage_report" type="object">
Present once `status` reaches a terminal value with a usable result —
today that means `completed` (`completed_with_partial` is
[reserved](/reference/status) and not currently emitted). Shape below.
Present once `status` reaches a terminal value with a usable result
(`completed`). Shape below.
</ResponseField>

### `triage_report`
Expand Down Expand Up @@ -117,28 +124,18 @@ The response is the scan record. Fields you should rely on:
</ResponseField>

<ResponseField name="evidence_index" type="object[]">
Per-URL evidence the contextual model cited. See
Per-URL evidence Tumban cited in support of the decision. See
[Evidence index](/concepts/evidence-index).
</ResponseField>

<ResponseField name="strategy_scores" type="object" required>
Internal per-strategy scores: `blocklist`, `content_safety`, `llm`.
Useful for debugging unexpected recommendations.
</ResponseField>

<ResponseField name="judge_model_invoked" type="boolean" required>
Whether the judge model was invoked to resolve a borderline score.
</ResponseField>

## Coverage

The scan record's `triage_report` does **not** include `coverage` —
that field is delivered as a top-level key in the
[webhook payload](/webhooks/payload). When polling, read the
`coverage` object (delivered alongside the triage report on the webhook
side) to see what was skipped; today the scan's `status` is `completed`
even when individual steps failed (`completed_with_partial` is
[reserved](/reference/status) and not currently emitted).
Poll responses include the [`coverage`](/concepts/coverage) object too
— it lives at `triage_report.coverage` on `GET /api/v2/scans/{scan_id}`.
On the [webhook payload](/webhooks/payload) the same object is delivered
as a top-level `coverage` key. Same fields either way; only the
placement differs. The scan's `status` is `completed` even when
individual steps were skipped — read `coverage` to see what ran.

## Example

Expand All @@ -156,6 +153,7 @@ curl https://api.tumban.com/api/v2/scans/550e8400-e29b-41d4-a716-446655440000 \
"created_at": "2026-04-29T12:00:00.123456+00:00",
"processing_started_at": "2026-04-29T12:00:01.234567+00:00",
"processing_completed_at": "2026-04-29T12:01:38.987654+00:00",
"is_banned": false,
"callback_url": "https://your-app.example/webhooks/tumban",
"metadata": {"reviewer_id": "rv_42"},
"webhook_delivered_at": "2026-04-29T12:01:39.345678+00:00",
Expand All @@ -167,8 +165,6 @@ curl https://api.tumban.com/api/v2/scans/550e8400-e29b-41d4-a716-446655440000 \
"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",
"strategy_scores": {"blocklist": 50, "content_safety": 0, "llm": 85},
"judge_model_invoked": false,
"evidence_index": [
{
"ref": "link_1",
Expand All @@ -182,10 +178,7 @@ curl https://api.tumban.com/api/v2/scans/550e8400-e29b-41d4-a716-446655440000 \
```

<Note>
The response also includes internal fields not listed above —
`canonical_url`, `username`, `platform`, `last_scanned_at`, `bio`,
`profile_image_url`, `banner_image_url`, `social_links`,
`direct_links`, `blob_references`, `updated_at`, and `org_id`. These
The response also includes internal fields not listed above. These
reflect the underlying scan record and are subject to change. Do not
rely on their names, types, or presence; treat them as opaque.
</Note>
Expand All @@ -208,7 +201,5 @@ read-only sections:
codes, reason summary.
- **Coverage** — which analysis steps ran, login-blocked URLs,
referrer match counts.
- **Strategy scores** — internal per-strategy scores. Useful for
debugging an unexpected recommendation.
- **Raw JSON** — collapsible *"Show full document"* panel that
exposes the entire scan record.
71 changes: 0 additions & 71 deletions api/usage/priority.mdx

This file was deleted.

94 changes: 0 additions & 94 deletions api/usage/scans.mdx

This file was deleted.

68 changes: 0 additions & 68 deletions api/usage/totals.mdx

This file was deleted.

Loading