Skip to main content

Why results are asynchronous

Processing a Task — reading documents, extracting structured records, and validating them — takes longer than a single HTTP request should wait. So the API is asynchronous: POST /task/create returns immediately with the Task’s initial details, status: "pending", and an empty verdicts list. The result does not exist yet. You learn the outcome one of two ways:
  • Option A — poll GET /task/get until the Task reaches a terminal status.
  • Option B — supply a callback_template at create time so Synthpop calls you when the Task finishes (opt-in, org-gated).
Both observe the same thing: the Task’s status moving toward a terminal value.

Task statuses

A Task’s status is one of the values below. Three are terminal — once a Task reaches one, it will not move again on its own.
A Task can stop at waiting instead of reaching a terminal status. waiting means Synthpop needs more documents or data before it can continue — it is not a failure and it is not terminal. A polling loop that only checks for terminal statuses will spin forever on a waiting Task. Handle waiting explicitly; see Responding to waiting Tasks.

Option A: poll GET /task/get

Retrieve a Task by either its Synthpop uuid or your own external_id — exactly one, never both:
  • Supplying neither or both returns 400.
  • A well-formed identifier that matches no Task returns 404.
Poll on an interval (with backoff), and stop when status is terminal — or branch to your resume logic when it is waiting.
Read GET /task/get results only after the Task reaches a terminal status. On a completed validation Task you will find per-code verdicts, plain-English verdict_summaries, and any issues. See Results for the response shape.

Option B: callback on completion

Instead of polling, pass a callback_template when you create the Task. It is a URL pattern that Synthpop issues a GET request against when the Task finishes processing. Two placeholders are expanded in the URL:
cURL
When the Task above finishes, Synthpop issues:
If you had omitted external_id, the order parameter would be the string null:
The callback signals that the Task finished. Your handler should then call GET /task/get to read the actual result — treat the callback as a nudge to fetch, not as the payload itself.
A callback is an unauthenticated notification. It is a plain GET to the URL you supplied, carrying no secret, signature, or proof that it came from Synthpop. Treat it as an untrusted nudge: on receipt, call GET /task/get (with your bearer token) to fetch the authoritative Task state rather than trusting anything in the callback request. Callback timing and retry behavior are not guaranteed, so polling remains the reliable path — a callback can only ever save you a poll, never replace one.
Callbacks are opt-in and org-gated. A callback_template fires only if your organization has external callbacks enabled. You can confirm this from the org_settings.external_callback_enabled flag returned by POST /auth/get_token. If callbacks are not enabled for your org, the template is ignored and you must poll. Contact your Synthpop representative to enable them.

Load backpressure

When your organization submits work faster than its provisioned capacity, a Task whose task_type is deferrable is parked server-side rather than running right away — but it reports as pending to you the whole time. It is promoted automatically once capacity frees up; no action is needed on your side. Keep polling (or wait for the callback) as usual. There is a per-organization cap on how many Tasks can be queued this way. When the deferred queue is full, POST /task/create is rejected with 429 Too Many Requests. Back off and retry the create later.
The 429 response is part of the API contract but is not yet present in the committed OpenAPI snapshot that powers the API reference. Handle 429 on POST /task/create anyway; the committed reference will include it once the schema-regeneration job lands.

Which should I use?

Poll GET /task/get

Works for every organization, no configuration. Best for scripts, batch jobs, and integrations that already have a work loop. Use backoff and handle waiting.

Callback template

No polling load; near-real-time notification. Requires external_callback_enabled and a reachable public HTTPS endpoint. Still fetch the result with GET /task/get.

Responding to waiting Tasks

Resume a Task that paused at waiting by adding files or data.

Errors

The full status-code and error-body reference, including 429.