Aller au contenu

Troubleshooting

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

Find the message from the response in the tables below. Per-record messages appear in results[].errors; whole-request messages appear in the detail field of an error response.

HTTP Message Cause Fix
401 api key required No Authorization header, or you used a browser session instead of an API key Send Authorization: Bearer spk_…
401 unsupported authorization scheme The header doesn’t start with Bearer Check spelling and the single space
401 invalid api key The key is mistyped, revoked or expired Check your secret manager; ask an administrator for a new key
403 api key lacks scope ingest:write The key was created for something else, e.g. decide Create a key with ingest:write
404 The server isn’t running the ingest role, or the path is wrong Check the path is /api/v1/ingest/…; ask your operator to enable ingest
413 at most N items per request The operator lowered the batch limit (SP_INGEST_MAX_BATCH) below 500 and the batch is larger Split the batch to at most N records
413 request body too large Body over 8 MiB (or the operator’s SP_INGEST_MAX_BODY_BYTES) Split the batch
422 validation failed At least one record breaks the format rules. The errors list gives each problem and its location, e.g. body.items[37].direction Fix those records. The whole batch was refused; resend all of it
503 ingest temporarily unavailable; retry the batch The queue couldn’t accept anything Wait and resend the same batch
421 this API key belongs to the … region; send requests to … Your SpeculaPro is hosted in more than one region and the request went to the wrong one, or your workspace was moved Nothing was accepted. Change your base URL to the base_url in the response and resend. See Regions for integrators
503 the workspace is read-only while it is moved to another region; try again shortly A planned move between regions is starting Keep the batch and resend after Retry-After
503 the workspace is being moved to another region; retry shortly The workspace is between regions Keep the batch and resend after Retry-After; once the move is done, resend to the new region’s base URL
500 Unexpected fault Wait and resend the same batch. If it persists, give your operator the time of the request
errors[].location ends in Likely cause
.direction, .type, .channel, .status A value not in the allowed list, e.g. "inbound" instead of "in", or upper case "MOMO" instead of "momo"
.occurred_at, .onboarded_at, .opened_at Missing (for occurred_at), or not a full date-time with timezone, e.g. "2026-10-09 08:14"
.date_of_birth, .as_of Not in YYYY-MM-DD form
.amount_minor Negative, a decimal (4950.00), or a string ("495000")
.currency, .country, .nationality Not upper case, or wrong length ("ghs", "GHA")
.rate Sent as a number (15.25) instead of a string ("15.25"), or negative
.mcc Not exactly four digits
.attributes More than 64 keys
.items Empty items array, or more than 500 records (the hard ceiling)
Message Cause Fix
occurred_at is required The time was sent as an empty “zero” date (0001-01-01T00:00:00Z), usually a default value in the exporting system Send the real time
occurred_at is in the future More than 5 minutes ahead of SpeculaPro’s clock. Usually a local time sent as UTC: 08:14 Accra time sent as 08:14Z is fine (Ghana is on UTC), but Lagos 08:14 sent as 08:14Z is an hour in the future Send an explicit offset (+01:00), or convert to UTC first. Check your server clocks are synchronised
occurred_at is before 2000 A corrupted or placeholder date Send the real time
external_id has leading or trailing spaces Padding from a fixed-width file or a database CHAR column Trim the value, the same way every time
currency must be an ISO 4217 code Not three capital letters Use GHS, USD, XOF…
ip is not a valid IPv4/IPv6 address Includes a port (41.66.12.9:443), or is a hostname Send the bare address
external_id repeated in this batch with different content Two different transactions in one batch share an external_id Your references aren’t unique. Fix the source system’s ID generation
external_id was already used for a different transaction You sent a transaction with an external_id SpeculaPro already holds, but with something changed If it’s a correction or reversal, send a new transaction (how). If nothing should have changed, check whether your exporter rewrites fields such as the time format or attributes
no FX rate for USD→GHS on or before 2026-10-09; load rates via /api/v1/ingest/fx-rates No rate for that currency dated on or before the transaction Load rates, wait a few minutes, resend
latest FX rate for USD→GHS is from 2026-09-28, too old for 2026-10-09 Rates stopped being loaded Load current rates, resend. Fix the daily rate job
temporarily unavailable, retry this item (status retry) The queue didn’t confirm this record Resend it unchanged
Message Cause Fix
phone is not a valid number Fewer than 8 or more than 15 digits after conversion, or a local number (starting 0) in a workspace whose country SpeculaPro can’t convert Send the number in + international format. See How phone numbers are read
email is not valid No @ Correct it or leave it out
invalid data: violates … The record broke a database rule. The name after violates says which Check values against the field table
Status stale The version you sent is equal to or lower than the stored one Expected after a resend: nothing changed. If you expected the update to apply, your version didn’t increase; see Versions
Message Cause Fix
currency must be an ISO 4217 code Not three capital letters Use GHS, USD, XOF…
invalid data: violates … The record broke a database rule Check values against the field table
Status stale The version isn’t higher than the stored one As for customers
Message Cause Fix
quote equals the workspace base currency A rate for the base currency itself Leave it out
rate must be greater than zero A rate of zero, written any way ("0", "0.000"). Only that rate is rejected; the rest of the batch is stored. (A negative rate or text that isn’t a number fails the whole request with 422 instead.) Send the real rate, or leave that currency out for the day
Message Cause Fix
occurred_at is more than 180 days ago A backfill reaching too far back Send events from the last 180 days only. Older ones can’t affect any rule
ip is not a valid IPv4/IPv6 address Malformed address Send the address alone, without a port
422 naming type or channel A value outside the allowed list. Event channels differ from transaction channels: mobile_app, online, ussd, branch, agent, atm, call_centre, api, other See Account events

The other event rejections are the same as for transactions.

Symptom Cause Fix
Amounts in CFA francs look 100 times too large Sent in “centimes” XOF and XAF have no decimals. See Currencies and FX
Foreign-currency amounts look about 200 times too small The FX rate was loaded inverted rate is base per 1 unit of foreign currency. See FX rates
Customer details disappeared after an update The update left fields out Updates replace the whole record. Always send the full customer
Customer updates always come back stale Your version doesn’t increase between updates (for example a fixed value, or a counter that restarted) Use a value that only ever increases, such as last-updated time in milliseconds. See Versions
Customers show as stubs ("_stub": true) Transactions or accounts arrived, but the customer record never did Check the customer feed is running and covers everyone
Transfers between your own customers aren’t linked SpeculaPro didn’t know the numbers were phone numbers (no mobile-money provider and no identifier_type: "msisdn"), so they weren’t converted to one format; or bank account numbers differ in more than spacing and case Send provider or identifier_type. See How identifiers are normalised
Old transactions counted twice Resent more than 90 days after first being received See The 90-day window
A fraud rule that counts failed OTPs or PINs never fires No account events arrive, or they carry a customer_external_id that doesn’t match the transactions’ Send account events with the same customer references as your transactions
New-device, shared-device or impossible-travel rules never fire Transactions don’t carry device_fingerprint, or geo_lat and geo_lon Add them to transactions. Account events alone don’t set a device as known or move the customer’s location
A short-window rule (15 minutes or less) misses activity in a backlog The transactions or events arrived more than about 20 minutes late Send in real time. See Late and backdated data
A failed-OTP count reads one too many An accepted event was resent more than 30 minutes later Resend only retry items, straight away. See Sending the same event twice