Errors
Answers and what to do
Section titled “Answers and what to do”Only 202 confirms acceptance of an event. For a file upload, 201 confirms that MarsX stored the file.
| Status | Meaning | What you do |
|---|---|---|
202 |
The event passed verification and is stored safely. It is queued. The body says accepted or duplicate. It is not yet applied |
Done. Do not resend |
201 |
A file upload is stored safely. A repeat of the same file also gets 201 with result duplicate |
Done |
400 |
Seen only by an authenticated sender. The body is not valid JSON, the event type is unknown, data.record_action does not match type, or a field is missing or not valid for this action |
Fix it. Do not retry the same request |
401 |
The signature is missing or wrong, the timestamp is outside the window, or the URL or environment is wrong. All of these give the same answer | Check the key, the clock, the URL and the environment. Do not retry the same request |
403 |
A valid token without the read scope | Ask for a client with the right scope |
404 |
An unknown event or lead, for an authenticated caller only. The events endpoint never answers 404 |
See the notes in Send leads automatically |
410 |
A cursor older than the replay window | See cursor rules |
413 |
The body is above the event limit of 32,768 bytes, or above the transport cap of the route (1 MiB, or 10 MiB for file upload). Limits lists both | Fix it. Do not retry |
415 |
The content type is not application/json |
Fix it. Do not retry |
429 |
Too many requests. The Retry-After header says when to try again. It does not confirm acceptance |
Wait at least Retry-After, then retry the same event with the same webhook-id |
502, 503, 504, other 5xx, a timeout or a dropped connection |
A temporary fault. The event may already be stored. None of these confirms acceptance | Slow down. Wait at least Retry-After when present. Retry with the same webhook-id and body, a fresh timestamp and a fresh signature |
“Do not retry” means do not run an automatic retry loop. The event is still owed. After you fix the cause, send it again with the same webhook-id, a fresh timestamp and a fresh signature. Never drop a rejected withdrawal or deletion.
MarsX sends 202 only after the event is stored. If storing fails, MarsX answers 5xx.
The 202 body
Section titled “The 202 body”{ "result": "accepted", "webhook_id": "msg_test_0001", "request_id": "req_example_0001"}result |
Meaning |
|---|---|
accepted |
The event passed verification and is stored. It is queued for processing. It is not yet applied |
duplicate |
MarsX has already received this webhook-id. Nothing new was stored |
request_id is a MarsX reference for support.
Problem details
Section titled “Problem details”Errors use problem details, a standard JSON error format (RFC 9457), with the media type application/problem+json. An error never contains personal data.
| Member | Meaning |
|---|---|
type |
A URI that names the problem type |
title |
A short title |
status |
The HTTP status |
detail |
A sentence that says what to check |
instance |
A MarsX reference. Quote it when you contact MarsX |
errors |
On 400, a list of pointer and message pairs |
A 400 for an authenticated sender:
{ "type": "urn:marsx:problem:invalid-event", "title": "The event does not match the lead contract", "status": 400, "detail": "One or more fields are missing or not valid for this action.", "instance": "req_example_0005", "errors": [ { "pointer": "/data/contact_consent", "message": "Required for lead.new and lead.update. The only accepted value is yes." } ]}A 401:
{ "type": "urn:marsx:problem:unauthorized", "title": "Authentication failed", "status": 401, "detail": "The request could not be authenticated. Check the key, the clock, the URL and the environment.", "instance": "req_example_0006"}Order of checks
Section titled “Order of checks”MarsX authenticates first on the events endpoint. A request that fails authentication gets 401 before any content type, size or field check. So 400, 413 (above 32,768 bytes) and 415 are seen only by an authenticated sender.
A body above the transport cap of its route gets 413 before authentication, whatever the signature or the connection reference. The transport cap is 1 MiB for every path except the file upload path, which has 10 MiB. For a given route, that 413 is the same for a known and for an unknown path.
Why the 401 is generic
Section titled “Why the 401 is generic”A missing or wrong signature, a timestamp outside the window, an unknown connection path, an inactive connection and a credential from another connection all get exactly the same response: the same status, headers, problem type, title, detail and body shape. Only the Date header and the instance differ.
This stops a caller who is not authenticated from learning which connections MarsX has. The instance value lets MarsX find the exact cause in its own logs.
The 404 answers of the status call and of your own lead endpoint apply only to an authenticated caller’s own connection or data.
What MarsX keeps when it refuses an event
Section titled “What MarsX keeps when it refuses an event”A refused event (400, 413 or 415 to an authenticated sender) stores no lead data. MarsX keeps a restricted rejection record: the reason, the instance reference, the connection, the event type, and the lead ID if it could be read. The record holds no customer data. A refused lead.withdraw or lead.delete also alerts the MarsX privacy operator. You still have to fix the event and send it again.
Problem types
Section titled “Problem types”type |
Status | Used for |
|---|---|---|
urn:marsx:problem:unauthorized |
401 | Every failed authentication on the events endpoint |
urn:marsx:problem:invalid-event |
400 | An event that does not match the contract |
urn:marsx:problem:payload-too-large |
413 | A body above the transport cap of its route, or above a content limit after authentication |
urn:marsx:problem:unsupported-media-type |
415 | A content type that is not application/json |
urn:marsx:problem:rate-limited |
429 | A request above the sending budget |
urn:marsx:problem:server-error |
5xx | A temporary MarsX fault |
urn:marsx:problem:invalid-token |
401 | A missing, expired or invalid OAuth token |
urn:marsx:problem:forbidden |
403 | A valid token without the read scope |
urn:marsx:problem:not-found |
404 | An unknown event or lead, for an authenticated caller |
urn:marsx:problem:invalid-query |
400 | A bad query on a read call, for example limit out of range |
urn:marsx:problem:cursor-expired |
410 | A cursor older than the replay window |
You may use your own type URIs on the endpoints you host. MarsX acts on the status code (for example 410), not on the URI. Treat an unknown type as information only.
