Beta
Error Handling
How the Session and Workflow APIs report errors, how to branch on them, and the limits worth knowing before you go live.
How errors arrive
An error arrives in one of two JSON shapes, and which one you get follows which layer answered, not the status code.
Content-Type | Body | Read |
|---|---|---|
application/json | The messages envelope. | messages[].code, such as VALIDATION_ERROR or SESSION_EMPTY. |
application/problem+json | A problem document: type, title, status, detail and instance, with no messages key. | type, compared as the whole URI. |
A 400 and a 409 can arrive in either shape. A 401, 403, 404 or 500 from the service is always a problem document. These are the problem types the Session and Workflow APIs return:
type | Status | Meaning |
|---|---|---|
about:blank | 400, 401, 403, 404, 500 | The status alone describes the problem: a body that could not be read as the request, no credential at all, a denial before the operation ran, a path this API doesn’t serve, or an unhandled failure. |
https://pointservices.com/problems/invalid-token | 401 | A token was sent and refused. Get a fresh one. |
https://pointservices.com/problems/not-authorized | 403 | You are signed in, and you may not act on this resource or product. |
https://pointservices.com/problems/not-found | 404 | The identifier you sent did not resolve. |
https://pointservices.com/problems/invalid-request | 400 | The Content-Type header names a character set the service can’t use. |
https://pointservices.com/problems/concurrent-modification | 409 | Another request changed the same resource first, and nothing from yours was applied. Read it again before you resubmit. |
The rules that follow from this:
- Branch on the
Content-Typefirst, then onmessages[].codeortype. Compare the media type only, ignoring parameters such ascharset. Check thatmessagesexists before you readmessages[0].code: on several endpoints the problem document is the common case, not the exception. - Some rejections carry no JSON body at all. The edge in front of the service refuses a POST without
Content-Type, or a value that looks like SQL or markup, with a 403 and an HTML body, and a rate-limited request with a bare 429. Write your client to tolerate an error it can’t parse. - Treat an unrecognized message code as non-retryable. The vocabulary is closed but additive; meeting a new code means stop, not retry.
- What a 500 means depends on the call. On the reads it means nothing happened, so read again. On Start a Session and Stage Data the 500 is not stored, so send the same request again with the same
Idempotency-Key: if the failed attempt’s work was kept you get its original response, and if not it runs again, so you end up with one session or one snapshot either way. On Start a Workflow, Start a Workflow in a Session and Reconfirm a Workflow, the outcome is unknown, not that nothing happened. With anIdempotency-Key, a 500 on those three is stored and every retry under that key returns it, so re-read, or search bycorrelationId, then send the call under a new key only if it didn’t happen. Without a key, retrying blind is how one workflow becomes two. On Edit a Workflow, send the same request again: a repeated outcome report is recorded again and changes no answer. - Send an
Idempotency-Keyon every POST you might retry, except Edit a Workflow, which takes none. A retry under the same key returns the first response instead of doing the work again. See Retrying Safely. - Quote
instancewhen you report an error. It is writtenurn:pps:request:<id>, and the id is the same one thex-pps-request-idresponse header carries. It is what lets PPS find that one request.
Things to know
- A session never expires, and it is not a login session. Holding a
sessionIdis not permission to use it: every call is authorized on its own. dataStagednever returns tofalseonce a stage has succeeded. Re-staging replaces the snapshot; nothing empties a session.- A 409
SESSION_EMPTYmeans stage first. It is the one 409 you can fix on your own: stage data, then start the workflow again. - A rejected stage changes nothing. The previous snapshot stays current, and no partial one is recorded.
statusis one of four lowercase values:processing,complete,failedandcancelled. Branch on it, not on message codes.- A request’s
correlationIdis limited to 255 characters, after trimming. On a session start, a workflow start (direct or in a session) or a reconfirm, a longer value is a 400 and nothing is stored. A term’s owncorrelationIdhas the same limit, but a longer one is ignored rather than rejected; see Correlation ids on terms. - Find Workflows returns at most 100 workflows, newest first, with no paging, and it reads at most the newest 1,000 matching runs. Make your correlation ids distinctive.
- A reconfirm body decides what runs. No body, or
{}, re-runs against the session’s current data. A body withtermsrecords a new snapshot of the session, stated in full, and re-runs against it. - Every POST needs
Content-Type: application/json, including a session start or a reconfirm with no body.