Errors

Every code the error envelope carries, what causes it, how to fix it and whether to retry.

A refusal answers a 4xx or 5xx status with a JSON body: error.code says what happened and error.message is one fixed sentence. Branch on the code, not on the status or the sentence: two codes can share a status. Some codes add extras: errors (per item), latest, rev, epoch, missing and retry_after.

json
{
  "error": {
    "code": "validation_failed",
    "message": "Some items could not be saved. Each error says why.",
    "errors": [
      {
        "unit_id": "u-01oso1x",
        "error": "outside_window",
        "message": "That time is outside the window."
      }
    ]
  }
}

Codes

StatusCodeWhat happenedWhat to doRetry
400bad_requestThe request is not valid: a path value, a query value or a body field is missing, malformed or out of range.Read the message, which names up to three fields and what is wrong with each, correct the request and send it again.No
401invalid_principalThe key is missing, malformed, unknown, revoked or expired; all of these answer the same way.Send the whole key as Authorization: Bearer rwaff_k_.... If it still fails, check under API and MCP in the portal that the key is active, or create a new one.No
403forbiddenThe key is valid but cannot do this for this affiliation: the affiliation is not one of the key's, or the person who made the key lacks the role.Call GET /v1/affiliations to see what the key can reach and with which role. A key made for other stations needs replacing.No
403read_onlyThe affiliation is read-only: the network paused or ended it, or the station outlet is inactive. Its history stays readable.Only reads work on this affiliation. Ask the network if you expected it to be live.No
403key_cannot_signA key asked to sign a week. Signing is an attestation, so only a person signed in to the portal can do it.Send the person to the portal's signing panel (over MCP, sign_week returns the link). Keys report times; people sign.No
403insufficient_scopeThe key does not carry the scope this endpoint needs (read, report or acknowledge).Scopes are fixed when a key is made. Create a key with the scope named on the endpoint's page and use it instead.No
404not_foundNothing was found for the values in the path: no audio is ready for the week yet, the upload id is unknown, or the record does not exist.Check the ids against GET /v1/affiliations and GET /v1/affiliations/{id}/weeks. For audio, wait until list-creatives shows mediaStatus ready.Yes
409stale_versionA newer version of the week exists than the one you sent: acknowledging the older one, or reporting dropped breaks by its break numbers after the show's breaks were renumbered, would be wrong.Read the week again, then acknowledge the latest version the error carries, or report the dropped breaks again with the new break numbers.No
409epoch_changedThe network reopened or changed the week after you read it, so the epoch you sent is out of date.Read the week again, take week.epoch from it, check your times still apply and send the batch again.No
409week_signedThe week is signed, so its affidavits can no longer change.Ask the network to reopen the week if something needs correcting.No
409sign_blockedThe week cannot be signed yet: items are still pending, or the broadcast week has not ended. missing lists what is left.Report the units and show days listed in missing, then sign in the portal after Sunday. No API call signs.No
409conflictThe week changed while the request was being handled.Read the week again, then retry with the values it now shows.Yes
409staleThe week changed after the log was read, so the matches were made against an older copy.Read the week again and upload the log again, or apply with the new epoch the error carries.No
409already_appliedMatches from this upload were already applied, and that result does not cover the units you sent now.Report the other times with report-affidavits. An upload is applied once; the repeat of the same choice is answered with replayed: true.No
409not_readyThe uploaded log is still being read, or reading it failed, so there is nothing to apply yet.Poll GET /api/uploads/{upload} with the same station key until it answers ready, then apply. After a failure, type the times instead.Yes
409nothing_to_matchNo unit in this week is waiting for a time, so there is nothing a log could match.Check the week and the station. Units become reportable once their window has closed.No
409nothing_to_applyThe upload has no matched lines to apply.Send the chosen items yourself, or report the times with report-affidavits.No
413payload_too_largeThe request body is over the limit: 256 KB of JSON (512 KB when applying log matches), or 10 MB for an uploaded log.Split a report into smaller batches (at most 2,000 items each), or upload one broadcast week per file.No
415unsupported_media_typeThe body was not sent as JSON.Send Content-Type: application/json with a JSON object body.No
415unsupported_fileThe uploaded file is not a log export the reader accepts.Upload the CSV, TSV, text, spreadsheet (xls or xlsx) or PDF your automation system saves.No
422validation_failedItems were refused. With all_or_nothing true nothing was saved; errors says why for each item.Fix each item named in errors (for example rev_conflict carries the current value) and send those items again.No
422upload_failedThe log could not be read within the request. upload_id names the upload.Try a CSV export of the log, or type the times with report-affidavits.No
429rate_limitedToo many requests: the key's bucket, a daily limit or the failed sign-in brake refused this one.Wait for Retry-After seconds, then retry. Pace calls with RateLimit-Remaining to stay clear of it.Yes
500not_savedThe change could not be saved, so nothing changed.Send the same request again with the same Idempotency-Key; a write that did save answers with its first result.Yes
500server_errorSomething went wrong on our side. The answer never carries internal detail.Retry once. If it keeps happening, quote the X-Request-Id header when you contact the network.Yes
502upstream_failedThe service behind the API answered in a way the portal could not use.Retry after a short pause. Reads are safe to repeat; repeat a write with the same Idempotency-Key. If a write keeps failing with that key, the key may already have been used for a request to another endpoint: read the week to see what was saved, then send the write with a new key.Yes
503unavailableThe service is not available right now: it could not be reached, or it is not set up yet.Retry after a short pause, backing off. Nothing about the request needs to change.Yes
503demo_modeThis copy of the portal runs on demo data, so the API is off. The body is exactly {"error":"demo_mode"}.Use the "Try it" panel on each endpoint page, which runs on the demo data without a key, or call the live portal.No

Every endpoint can answer 401 invalid_principal, 429 rate_limited, 500 server_error, 503 unavailable; each endpoint page lists the others it can give.

Item errors

A batch report saves the valid items and lists the others in errors with a code each (with all_or_nothing true, one refusal saves nothing and answers 422). Each entry names its unit_id, or its vehicle_id and date.

CodeWhy the item was refused
rev_conflictThe item changed since you read it; current carries its value now. Re-apply your change to it.
not_reportableThe unit's window has not closed yet, or the show day has not ended: at the end of the station's usual hours when it gave them, otherwise at the end of the day in its time zone.
outside_windowAn aired time is outside the unit's window. Report it as outside with a reason.
invalid_timeThe time does not fit the status: an outside time inside the window on one of the unit's own days is aired.
invalid_dateThe date is not one the unit or show day can take.
reason_requiredoutside, not_aired and not_carried need a reason of 1 to 300 characters.
removedThe unit was removed in a later version.
not_foundNo such unit, or no such show day, in this week.
break_not_foundA dropped break is not a break of that show day (give its break number, counted straight through the show, and the hour that holds it).
local_breakA dropped break is a local break, which the network does not bill.

Retrying

  • Retry a Yes code after a pause that grows each time (for example 1, 2, 4 then 8 seconds), and a 429 after its Retry-After.
  • Repeat a write with the same Idempotency-Key: if the first attempt did save, the repeat answers its first result instead of recording twice.
  • Do not retry a No code unchanged: the same request gets the same answer.
  • The demo portal answers every API call with 503 and exactly {"error":"demo_mode"}; use the Try it panels there.