Errors and Limits
This page collects behavior that applies across the Partner API.
Error Envelope
Section titled “Error Envelope”Every non-2xx response uses the same JSON shape:
{ "code": "EVENT_NOT_FOUND", "message": "No event exists for that partner id", "correlation_id": "<CORRELATION_ID>"}Branch on code, not message. Messages are for logs and operator visibility.
Correlation IDs
Section titled “Correlation IDs”Send x-correlation-id when you have a trace ID:
curl -sS "$MESHI_BASE/auth" \ -H "Authorization: Bearer $MESHI_KEY" \ -H "x-correlation-id: partner-trace-001"The response echoes the effective correlation ID in the x-correlation-id header and JSON body. Include it in support requests.
Auth and Scope Errors
Section titled “Auth and Scope Errors”| Condition | Status | Code |
|---|---|---|
| Missing or malformed bearer header | 401 | UNAUTHORIZED |
| Token does not resolve to an active key | 401 | UNAUTHORIZED |
| Disabled service account | 401 | ACCOUNT_DISABLED |
| Token is not an org-scoped service-account key | 403 | SERVICE_ACCOUNT_REQUIRED |
| Key lacks the required method scope | 403 | INSUFFICIENT_SCOPE |
| Request requires an org but none is available | 403 | PARTNER_ORG_REQUIRED |
Common Error Codes
Section titled “Common Error Codes”| Code | Typical cause | Integration action |
|---|---|---|
INVALID_JSON | Request body is not valid JSON. | Fix serialization. |
INVALID_PARTNER_KIND | kind fails the documented pattern. | Fix the kind value. |
INVALID_PARTNER_ID | Partner ID fails the documented pattern. | Fix the ID value. |
INVALID_IDEMPOTENCY_KEY | Missing, empty, or too-long idempotency key. | Generate a valid key. |
INVALID_ATTENDEES | Empty attendees array or over the row cap. | Fix or chunk the import. |
DUPLICATE_ATTENDEE_ID | Same attendee ID appears twice in one import payload. | Deduplicate before sending. |
PARTNER_ID_CONFLICT | Create attempted with an ID already mapped in your org. | Fetch and confirm before continuing. |
IDEMPOTENCY_KEY_CONFLICT | Same key reused for a different event or operation. | Use a fresh key. |
PAYLOAD_TOO_LARGE | Request body exceeds the byte limit. | Split the request. |
PARTNER_RATE_LIMIT_EXCEEDED | Request window exhausted. | Honor Retry-After. |
Route-specific errors are listed in the endpoint reference.
Idempotency
Section titled “Idempotency”Run-creating writes require idempotency_key:
PUT /events/:event_id/attendees:importPOST /events/:event_id/enrichment-runsPOST /events/:event_id/match-runsPOST /runs
Rules:
- Generate one key per logical operation.
- Reuse the same key for retries of that same operation.
- Do not reuse a key across different events or different logical operations.
First accepted use returns a created or accepted run. A replay in the same scope returns 200 with idempotent_replay: true. A conflicting reuse returns 409 IDEMPOTENCY_KEY_CONFLICT.
Async Statuses
Section titled “Async Statuses”Async run status values:
| Status | Terminal? | Meaning |
|---|---|---|
queued | No | Accepted but not started. |
running | No | Work is in progress. |
succeeded | Yes | Completed without errors. |
partial | Yes | Completed with per-item errors. |
failed | Yes | Run failed. |
Poll GET /runs/:run_id until the status is terminal.
Pagination
Section titled “Pagination”List endpoints use cursor pagination:
limitdefaults to 50 and maxes at 100.next_cursoris an opaque string ornull.- Pass
cursor=<next_cursor>verbatim. - Do not parse, decode, or construct cursors.
- Ordering is documented per endpoint.
Rate Limits and Backoff
Section titled “Rate Limits and Backoff”The default public contract is 600 requests per 60 seconds per API key. This limit can vary by environment or partner agreement.
When the limit is exceeded, the response is 429 PARTNER_RATE_LIMIT_EXCEEDED with a Retry-After header. Sleep for that many seconds before retrying. For repeated 429 or 5xx responses, use exponential backoff with jitter.
Body and Import Limits
Section titled “Body and Import Limits”Two independent size guards apply:
| Limit | Default | Failure |
|---|---|---|
| Request body size | 16 MiB | 413 PAYLOAD_TOO_LARGE |
| Attendees per import | 50,000 rows | 400 INVALID_ATTENDEES |
For large rosters, split attendees into chunks. Use a distinct idempotency key for each chunk, and poll each chunk’s run independently.
Webhooks in v0
Section titled “Webhooks in v0”webhook_url is accepted, stored, and echoed on run objects for forward compatibility. v0 does not deliver webhook callbacks. Do not build an integration that waits for a webhook; poll GET /runs/:run_id.