メインコンテンツまでスキップ

Errors

Audience

This API surface is for integration partners building on top of the Rokt network. Rokt ecommerce partners integrating placements on their own checkout should use the Rokt Ecommerce developer docs instead.

Every error response from the Partnerships API uses the same JSON envelope — identical in shape to success responses, just with error populated and data: null. This page is the reference for what each status means, the scenarios that produce them, and how to debug an unexpected response in front of you right now.

Response envelopeResponse envelope への直接リンク

Every response (success and error) has this shape:

{
"status": 400,
"error": "BadRequest",
"message": "store_identifier https://acme is not a valid URL",
"request_id": "0e3a1b9c-1234-4abc-9def-aaaabbbbcccc",
"data": null
}
statusinteger

Mirrors the HTTP status code (200 on success, 400/401/403/404/409/422/5xx on error).

errorstring | null

Stable error code keyed to the HTTP status — e.g. BadRequest (400), Unauthorized (401), Forbidden (403), NotFound (404), Conflict (409), ValidationFailed (422), RateLimitExceeded (429), InternalServerError (500). Safe to switch on. null on success.

messagestring

Human-readable description of what went wrong (or "ok" on success). Safe to surface to internal operators; do not display to end-merchants verbatim.

request_idstring

Server-generated correlation ID (UUID). Also returned in the X-Request-Id response header. Pass this to Rokt support so they can look up server-side logs for the call.

dataobject | array | null

Endpoint-specific payload on success. null on error.

ヒント

Always capture request_id from the response envelope. Including it in support tickets is the single biggest lever for fast resolution.

HTTP status codesHTTP status codes への直接リンク

StatusMeaningCaller action
400 Bad RequestValidation failed, payload malformed, missing required body fieldFix the payload, retry with a new Idempotency-Key
401 UnauthorizedMissing, expired, or invalid API tokenRotate the API token via your token-issuance integration
403 ForbiddenAPI token is valid, but either (a) you don't have permission to act on that account on behalf of your manager — your platform's account-to-account grant config is missing or hasn't synced — or (b) your X-Platform-Parent-Account-Id doesn't match the managed account's real parentSurface to ops — a manager-managed grant may have been revoked, or the header value is wrong
404 Not FoundResource doesn't exist, or isn't accessible to the callerVerify account_id and that it falls inside your manager-managed scope
409 ConflictIdempotency-Key conflict, or store_identifier already registered by another partnerSee common scenarios below
422 Unprocessable EntityMissing required header (most commonly X-Platform-Parent-Account-Id on a write), or payload is semantically invalid (e.g. unknown enum value)Add the missing header and retry with the same key
429 Too Many RequestsPer-partner rate limit hitHonor Retry-After, retry with the same Idempotency-Key. See Rate Limits for caps per endpoint
500 Internal Server ErrorRokt-side errorWait and retry with the same Idempotency-Key
501 Not ImplementedYou sent Prefer: respond-async but async mode isn't enabled for your platform yetDrop the header
502 / 503 / 504Rokt-side transient (downstream service unhealthy)Retry with backoff, same Idempotency-Key
警告

For 5xx responses, always retry with the same Idempotency-Key you used originally, within the 24-hour dedup window. A fresh key on retry can cause the same logical operation to run twice if the original eventually succeeded server-side.

Common error scenariosCommon error scenarios への直接リンク

422 — header X-Platform-Parent-Account-Id is required

You omitted the X-Platform-Parent-Account-Id header on a write call. The server requires it on all writes.

{
"status": 422,
"error": "ValidationFailed",
"message": "header X-Platform-Parent-Account-Id is required",
"request_id": "0e3a1b9c-...",
"data": null
}

Fix. Add X-Platform-Parent-Account-Id: <your-rokt-parent-account-id> to the request. Retry with the same Idempotency-Key — within the 24-hour dedup window the server collapses retries.

400 — store_identifier is not a valid URL

store_identifier must be a fully-qualified URL between 3 and 400 chars, scheme included. Sending a bare hostname is rejected.

{
"status": 400,
"error": "BadRequest",
"message": "store_identifier acme.myshopify.com is not a valid URL",
"request_id": "0e3a1b9c-...",
"data": null
}

Fix. Send https://acme.myshopify.com (or whatever the merchant's primary storefront URL is). Retry with a fresh Idempotency-Key.

400 — No partnership vertical mapping exists for MCL translation

Your partner taxonomy contains a vertical (or sub-vertical) ID that has no corresponding row in your vertical mapping. The server cannot translate it to Rokt's internal taxonomy, so the entire PUT is rejected atomically — no partial writes.

{
"status": 400,
"error": "BadRequest",
"message": "No partnership vertical mapping exists for MCL translation",
"request_id": "0e3a1b9c-...",
"data": null
}

Fix. Email smb-partnerships@rokt.com to add the mapping row. Include the exact partnerVerticalId and partnerSubVerticalId you tried, plus the partner-side name so the row can be filled in correctly.

409 — Rokt Account already exists (on register)

A different partner platform already owns this store_identifier. The Rokt account exists, but it's attached to another integration — registration cannot transfer ownership automatically.

{
"status": 409,
"error": "Conflict",
"message": "Rokt Account already exists",
"request_id": "0e3a1b9c-...",
"data": null
}

Fix. Surface this exact message to the merchant in your onboarding UI:

There is an issue with account creation that requires further review. Please email [Partner Platform Support].

Do not retry with a modified store_identifier to work around this — the conflict is the system telling you a real ownership question needs to be resolved by humans.

400 — Missing required non-empty parameter Idempotency-Key

Every write call (POST, PUT) requires the Idempotency-Key header. It must be a non-empty UUID.

{
"status": 400,
"error": "BadRequest",
"message": "Idempotency-Key header required for partnership writes",
"request_id": "0e3a1b9c-...",
"data": null
}

Fix. Generate a UUID per logical operation client-side and pass it as Idempotency-Key: <uuid>. See Idempotency Keys for how to scope the key across retries.

409 — Operation in progress / Idempotency-Key body mismatch

You reused an Idempotency-Key either while the original call is still being processed, or with a different body than the cached one. The server won't run the same key twice concurrently, and won't silently overwrite a cached response with a new payload.

Fix. Either wait briefly and retry the same call, or — better — poll the operation directly:

curl https://accounts.rokt.com/v1/partnership/operations/$OPERATION_ID \
-H "Authorization: Bearer $TOKEN" \
-H "X-Platform-Parent-Account-Id: $PARENT"

The operation_id is returned in the X-Operation-Id response header on every write. See Operations.

429 — Rate limit exceeded (honor Retry-After)

You exceeded the per-partner rate limit for this endpoint. The server returns the standard envelope plus a Retry-After response header carrying an integer number of seconds to wait before retrying.

{
"status": 429,
"error": "RateLimitExceeded",
"message": "rate limit exceeded for partnership writes; retry after 30s",
"request_id": "0e3a1b9c-...",
"data": null
}

Response headers (relevant subset):

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-Request-Id: 0e3a1b9c-1234-4abc-9def-aaaabbbbcccc

Fix. Sleep for Retry-After seconds, then retry with the same Idempotency-Key you used originally. Reusing the key inside the 24-hour dedup window guarantees the server collapses retries to a single logical operation — a fresh key here would risk running the write twice if the original eventually succeeded server-side.

curl backoff snippet (writes headers to a file, parses Retry-After, sleeps, retries with the same key):

KEY=$(uuidgen)
while true; do
STATUS=$(curl -s -o body.json -D headers.txt -w '%{http_code}' \
-X PUT https://accounts.rokt.com/v1/partnership/accounts/$ACCOUNT_ID/status \
-H "Authorization: Bearer $TOKEN" \
-H "X-Platform-Parent-Account-Id: $PARENT" \
-H "Idempotency-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }')
if [ "$STATUS" != "429" ]; then break; fi
WAIT=$(grep -i '^Retry-After:' headers.txt | awk '{print $2}' | tr -d '\r')
sleep "${WAIT:-30}"
done

Python equivalent (using requests):

import time, uuid, requests

key = str(uuid.uuid4())
while True:
r = requests.put(
f"https://accounts.rokt.com/v1/partnership/accounts/{account_id}/status",
headers={
"Authorization": f"Bearer {token}",
"X-Platform-Parent-Account-Id": parent,
"Idempotency-Key": key, # same key across retries
"Content-Type": "application/json",
},
json={"status": "active"},
)
if r.status_code != 429:
break
time.sleep(int(r.headers.get("Retry-After", "30")))

See Rate Limits for per-endpoint caps and Handling Failures for the broader retry contract.

400 — contact is only valid for hosted_invite payout setup

You sent experience: "embedded" together with a contact block. The two are mutually exclusive — contact is required for hosted_invite, forbidden for embedded.

Fix. Either drop the contact field (for embedded) or change experience to hosted_invite (if you want Rokt to email the merchant). See the Payout Setup section in the onboarding workflow.

Field-level validation errorsField-level validation errors への直接リンク

Common per-field rules that trip integrations during early onboarding. The full schema is in openapi.yaml; this is the short list of constraints worth knowing by heart.

POST /v1/accounts/register/partnershippost-v1accountsregisterpartnership への直接リンク

FieldRule
brandRequired, 1–200 chars
country_codeRequired, exactly 2 letters (ISO 3166-1 alpha-2). Lower-case input is normalized to upper-case server-side
store_identifierRequired, valid URL (must include scheme like https://), 3–400 chars
external_account_idRequired, non-empty. Idempotency key for registration — reusing it returns the same account_id
vertical_id / sub_vertical_idRequired. Must exist in your partner taxonomy and have a row in your vertical mapping
platform_parent_account_idRequired body field. Mirror it in the X-Platform-Parent-Account-Id header for clarity

PUT .../marketplacecontrolslistsput-marketplacecontrolslists への直接リンク

FieldRule
nameRequired, non-empty string
blockedVerticalsRequired array. Each entry must include partnerVerticalId + partnerSubVerticalId. policy defaults to Block if omitted
blockedVerticals[].policyOne of Allow, Block
blockedVerticals[].position1PolicyOptional. One of Allow, Block. Defaults to the entry's policy if omitted
domains[].policyOne of Allow, Block

PUT .../statusput-status への直接リンク

FieldRule
statusRequired. One of active, paused. Note: mixed is a read-only aggregate state — you cannot send it

POST .../payout-setuppost-payout-setup への直接リンク

FieldRule
providerRequired. Currently only stripe_connect is supported
experienceRequired. One of embedded, hosted_invite. Mutually exclusive with contact — see below
contact.emailRequired for hosted_invite. Forbidden for embedded. Sending contact with experience: "embedded" returns 400
any nested bank / card / routing / account_number / iban / ssn / tax / tax_id / paypal / external_account* / payout_destination / payment_method / cvc fieldsForbidden anywhere in the request. Returns 400. Stripe collects this data directly from the merchant

Debugging checklistDebugging checklist への直接リンク

When you're staring at an unexpected error, walk this list top-to-bottom before reaching out for support.

  1. Capture request_id from the response envelope (or the X-Request-Id response header — same value).
  2. Confirm Content-Type: application/json is set on every write call.
  3. Confirm X-Platform-Parent-Account-Id is set on every write — 422 is the canonical signal it's missing.
  4. Decode your API token and verify it hasn't expired (exp claim). API tokens are short-TTL — roughly 5 minutes.
  5. Confirm you're hitting accounts.rokt.com/v1/partnership/* or accounts.rokt.com/v1/accounts/register/partnership. No other Rokt host is partner-callable.
  6. If a write returns a 4xx but you suspect a server bug, retry with ?dry_run=true to isolate whether the payload is at fault or the server is. Dry-run runs the full validation without persisting state. See Dry-Run Mode.
  7. For 5xx responses, retry with the same Idempotency-Key inside the 24-hour dedup window. Do not generate a new key on retry.
  8. If all else fails, email smb-partnerships@rokt.com with the request_id, the approximate timestamp of the call (UTC), and the endpoint you hit.
備考

Why request_id matters. Rokt threads it through every server-side log entry for your call. Pass it back in a support ticket and the team can find the exact failure without paging through traffic.

この記事は役に立ちましたか?