Working with async checks
Submit, poll at a sane interval, handle every final status, cancel when the caller gives up, and never leave credits reserved.
A check is a job. POST /v1/checks accepts it and answers with an id in well under a second; the work runs on Silvertext's side and you read the result back by id. This guide is the lifecycle in full.
Statuses
| Status | Phase | What it means |
|---|---|---|
queued | Waiting | Accepted and reserved; a worker will pick it up. |
extracting | Running | Reading the file, OCR for scanned PDFs and images. |
analyzing | Running | Language detection, grammar, style and AI passes. |
searching | Running | Web search and source fetching for plagiarism matches. |
scoring | Running | Verdicts, scores and the report assembled. |
done | Final | The report is ready; credits are settled. |
rejected | Final | The document could not be checked after acceptance (rejection.code says why). No charge. |
failed | Final | Something broke on our side. No charge; safe to resubmit. |
cancelled | Final | You cancelled it. No charge. |
While a check runs, progress climbs from 0 to 1 and phase is a short label you can show a user.
Polling
Poll GET /v1/checks/{id}?view=summary. The summary view is the scalars and scores, a few hundred bytes, so it costs nothing to poll and counts one request against the per-minute limit.
- Start at 2 to 3 seconds between polls. Most checks finish in about a minute; a 25,000-word document with many sources can take several.
- Back off gently on long checks: 3 seconds for the first minute, 5 after that, capped at 10.
- Treat
done,rejected,failedandcancelledas final. Anything else is still running. - Give up on your side after a deadline you choose (ten minutes is generous), and cancel the check when you do, so its credits are released.
const FINAL = new Set(['done', 'rejected', 'failed', 'cancelled']);
export async function waitForCheck(id: string, { deadlineMs = 10 * 60_000 } = {}) {
const started = Date.now();
let delay = 3000;
for (;;) {
const check = await api(`/v1/checks/${id}?view=summary`);
if (FINAL.has(check.status)) return check;
if (Date.now() - started > deadlineMs) {
await api(`/v1/checks/${id}/cancel`, { method: 'POST' });
throw new Error(`check ${id} did not finish in time`);
}
await new Promise((r) => setTimeout(r, delay));
if (Date.now() - started > 60_000) delay = Math.min(delay + 2000, 10_000);
}
}Cancelling
Stops a queued or running check and releases its credit reservation. The API answers 202 immediately and the status becomes cancelled shortly after; a check that already reached a final status answers 409 already_final.
Deleting a report
Removes a finished report and its document from the account. A running check answers 409 still_running; cancel it first. Delete reports your product no longer needs, for example after you have copied the findings into your own store.
Concurrency
Five checks may be in flight per account at once. A sixth submission answers 409 concurrent_limit. A batch integration keeps a small pool of in-flight ids, polls them round-robin, and submits the next document as each one finishes; Batch checking has the pattern. Do not retry a 409 in a tight loop; wait for a slot.
Guides
The patterns behind a solid Silvertext integration: the check lifecycle, choosing checks, reading the report, files, idempotent retries and rate limits.
Choosing which checks run
The options object turns each category on or off, register sets the word-choice rules, and citationStyle picks APA, MLA or Chicago.