Aller au contenu

Responses and statuses

Ce contenu n’est pas encore disponible dans votre langue.

There are two levels of answer:

  1. The HTTP status tells you whether SpeculaPro could process the request at all.
  2. When it could (200 OK), the body gives a status for every record in the batch.

A 200 does not mean every record was accepted. Always read the per-record results.

{
"accepted": 497,
"duplicate": 1,
"stale": 0,
"rejected": 2,
"retry": 0,
"results": [
{"index": 0, "external_id": "MOMO-2026-10-09-000184223", "status": "accepted", "id": "0199c8f2-41a7-7d02-b3e5-1f6a9c0e2b47"},
{"index": 1, "external_id": "MOMO-2026-10-09-000184224", "status": "duplicate", "id": "0199c8e9-1a02-7f3b-8c21-77d0e4a9b5c6"},
{"index": 2, "external_id": "MOMO-2026-10-09-000184225", "status": "rejected",
"errors": ["no FX rate for USD→GHS on or before 2026-10-09; load rates via /api/v1/ingest/fx-rates"]}
]
}
Field Meaning
accepted, duplicate, stale, rejected, retry How many records ended in each status. They add up to the number you sent
results One entry per record, in the same order as you sent them
results[].index Position of the record in your items array, starting at 0
results[].external_id Your reference (for FX rates, QUOTE@DATE)
results[].status See below
results[].id SpeculaPro’s identifier, when the record was stored
results[].errors Why the record was rejected or must be retried
Status What it means What your sender should do
accepted Stored. For transactions: safely on SpeculaPro’s durable queue Mark it sent. Nothing more
duplicate SpeculaPro already has exactly this transaction Mark it sent. This is normal after a retry
stale A customer or account update older than (or the same as) what SpeculaPro already holds Mark it sent. If you didn’t expect it, check your version values
rejected The record has a problem SpeculaPro can’t accept. Sending it again unchanged will fail again Log it with its errors, alert whoever owns the data, fix the source, then resend
retry SpeculaPro couldn’t take it right now (a temporary fault) Send the same record again, unchanged, after a short wait

These responses apply to the whole request and come as Problem Details JSON with a detail message. After a 4xx, nothing in the request was stored.

HTTP status Message (detail) Cause What to do
401 api key required, invalid api key, unsupported authorization scheme Missing, wrong, expired or revoked key Check the key. See Getting an API key
403 api key lacks scope ingest:write The key can’t send data Use a key with ingest:write
403 code: workspace_suspended On the hosted service: SpeculaPro has suspended the workspace. The key is valid Keep what you were sending and contact SpeculaPro; retrying or rotating the key changes nothing. See A suspended workspace
404 The ingest role isn’t running on this server Ask your SpeculaPro operator
413 at most N items per request Only on installations where the operator has lowered the batch limit (SP_INGEST_MAX_BATCH) below 500, and you sent more than that Split the batch to at most N records
413 request body too large The body is over the size limit (8 MiB by default) Split the batch
422 validation failed At least one record breaks the format rules (see below), or the batch has more than 500 records Fix and resend the whole batch, split into batches of at most 500
503 ingest temporarily unavailable; retry the batch The queue couldn’t take any transaction Wait and resend the whole batch unchanged
500 An unexpected server fault Wait and resend the whole batch unchanged

After a 503 or 500, resending the batch unchanged is always safe, because records are identified by external_id: anything that did get stored comes back as duplicate (transactions) or stale (customers and accounts with the same version).

Before looking at individual records, SpeculaPro checks the whole request against the published format: required fields present, values from the allowed lists, correctly shaped dates and codes, lengths within limits. If any record fails these checks, the whole batch is refused and nothing in it is processed.

The response lists every problem with its location:

{
"title": "Unprocessable Entity",
"status": 422,
"detail": "validation failed",
"errors": [
{
"message": "expected value to be one of \"in, out, internal\"",
"location": "body.items[37].direction",
"value": "inbound"
}
]
}

body.items[37] is the 38th record you sent (counting from 0). The exact wording of message can vary.

Problems that are about the data rather than the format (a future date, a missing FX rate, an invalid phone number) are reported per record, with status rejected, and the rest of the batch goes through.

Limit Default Set by the operator with
Records per request 500 SP_INGEST_MAX_BATCH, which can only lower it. 500 is a hard ceiling: more than 500 records always fails with 422; more than a lowered limit fails with 413
Request body size 8 MiB SP_INGEST_MAX_BODY_BYTES

Batches of a few hundred records give the best throughput. Sending records one at a time works, but costs a round trip per record.