API reference/Affidavits

Report show airings

confirm

Report program carriage and dropped breaks.

POSThttps://affiliates.radioworkflow.com/api/v1/affiliations/{id}/weeks/{week}/show-airings
Confirm: this records an affidavit, the proof behind the network's invoices.

Certifies each show day: whether the station carried the show, the hours it aired, and whether the network's spots aired unedited.

  • carried: start and end (an end before start runs past midnight), and either unedited: true or dropped, the breaks the station did not air, each with its break number, counted straight through the show, the hour that holds it and a reason: [{"hour": 5, "breakNumber": 18, "reason": "..."}]. A dropped break must be a network break of that day, not a local one.
  • not_carried: with a reason.
  • pending: clears an earlier report, until the week is signed.

A show day can be certified once the station's usual hours for the show are over, or, when the station gave none, once the day has ended in its time zone. aired_date is for a show aired on another day, within 7 days after its date. Send each day's rev, and the week's epoch and version, from get-week unchanged: if the show's breaks were renumbered in a newer version, the report answers 409 stale_version and saves nothing. A saved dropped break that get-week shows as unreadable or unavailable is never sent back: report the day's dropped breaks by their current numbers. The batch rules are those of report-affidavits.

Authentication

Send a station key as Authorization: Bearer rwaff_k_.... A key with the report scope. Keys and scopes

Path parameters

idstring1 to 64 charactersrequired
The affiliation id from GET /v1/affiliations: one station's relationship with one network.
weekdaterequired
Monday of the broadcast week, YYYY-MM-DD. Any other day answers 400.

Request body (JSON)

epochintegerat least 0required
week.epoch from get-week, sent back unchanged. It moves when the network reopens the week, so a report built on an older read is refused with 409 epoch_changed.
versionintegerat least 1optional
The week version whose break numbers you used. Send the version you read: if the show's breaks were renumbered since, the report answers stale_version and saves nothing.
all_or_nothingbooleanoptionaldefault false
true saves nothing when any item is refused (422 validation_failed). The default false saves the valid items and lists the others in errors.
itemsarray of objectsrequired
The show days to certify, 1 to 2,000, each once.
vehicle_idstring1 to 20 charactersrequired
The show's vehicle id.
datedaterequired
The show day, YYYY-MM-DD.
revintegerat least 0required
The show day's rev from get-week.
statusenumrequired
Whether the station carried it.
carriednot_carriedpending
starttimeoptional
When the show started. Minutes after midnight (0 to 1439) or HH:MM, in the station's time zone.
endtimeoptional
When the show ended. Minutes after midnight (0 to 1439) or HH:MM, in the station's time zone.
aired_datedateoptional
The day it aired, when not its own date.
uneditedbooleanoptional
true when every network spot aired as delivered.
droppedarrayoptional
The breaks the station did not air, each with its break number, counted straight through the show, the hour that holds it and a reason: [{"hour": 5, "breakNumber": 18, "reason": "..."}].
reasonstring1 to 300 charactersoptional
Required for not_carried.

Idempotency

Send a new Idempotency-Key header with every request (8 to 48 letters, digits, dashes or underscores; a UUID is a good choice). To retry a request that timed out, send it again with the same key: if the first attempt saved, the repeat answers its first result instead of recording twice. A reused key records nothing new: here it answers its first result even when the body changed, and after a request to another endpoint it usually fails with 502 upstream_failed. Never reuse one for a new request. How it works

Response

200application/jsonThe show days saved, the items refused and the week's new state.

Response schema

savedShowAiring[]required
errorsItemError[]required
weekobjectrequired
week.state"signed" | "ready_to_sign" | "in_progress" | "published"required
week.epochintegerrequired
week.revintegerrequired
ShowAiring12 fields
keystringrequired
showIdstringrequired
datedaterequired
status"pending" | "carried" | "not_carried"required
startinteger (0 to 1439)optional
endinteger (0 to 1439)optional
uneditedbooleanoptional
dropped(object or object or object)[]optional
reasonstringoptional
source"portal" | "log_upload" | "rw_log" | "network" | "api" | "mcp"optional
airedDatedateoptional
revintegerrequired
ItemError6 fields
unit_idstringoptional
vehicle_idstringoptional
datedateoptional
error"rev_conflict" | "not_reportable" | "outside_window" | "invalid_time" | "invalid_date" | "reason_required" | "removed" | "not_found" | "break_not_found" | "local_break"required
messagestringrequired
currentAffiliateUnit or ShowAiringoptional
AffiliateUnit27 fields
idstringrequired
datedaterequired
daypartstringrequired
windowStartinteger (0 to 1439)required
windowEndinteger (0 to 1439)required
creativeIdstringrequired
advertiserstringrequired
productstringrequired
titlestringrequired
iscistringrequired
lengthintegerrequired
cartstringrequired
status"pending" | "aired" | "outside" | "not_aired"required
airedAtinteger (0 to 1439)optional
airedDatedateoptional
reasonstringoptional
source"portal" | "log_upload" | "rw_log" | "network" | "api" | "mcp"optional
addedInVersionintegerrequired
removedInVersionintegeroptional
kind"dated" | "weekly"required
weekStartdaterequired
allowedDaysdate[]optional
revintegerrequired
copyStatus"ready" | "to_follow"required
instructionsstringoptional
rwState"confirmed" | "not_confirmed"optional
flagsstring[]required

Errors

400bad_requestThe request is not valid: a path value, a query value or a body field is missing, malformed or out of range.
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.
403read_onlyThe affiliation is read-only: the network paused or ended it, or the station outlet is inactive. Its history stays readable.
403insufficient_scopeThe key does not carry the scope this endpoint needs (`read`, `report` or `acknowledge`).
409epoch_changedThe network reopened or changed the week after you read it, so the `epoch` you sent is out of date.
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.
409week_signedThe week is signed, so its affidavits can no longer change.
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.
415unsupported_media_typeThe body was not sent as JSON.
422validation_failedItems were refused. With `all_or_nothing` true nothing was saved; `errors` says why for each item.
500not_savedThe change could not be saved, so nothing changed.
502upstream_failedThe service behind the API answered in a way the portal could not use.
Possible on every endpoint
401invalid_principalThe key is missing, malformed, unknown, revoked or expired; all of these answer the same way.
429rate_limitedToo many requests: the key's bucket, a daily limit or the failed sign-in brake refused this one.
500server_errorSomething went wrong on our side. The answer never carries internal detail.
503unavailableThe service is not available right now: it could not be reached, or it is not set up yet.

Every code, its fix and when to retry

Rate limits

Failed sign-ins per address10 per minuteportal:auth
Burst per key60 per minuteportal:key
Calls per key600 per 10 minuteskey:{prefix}
Writes per key120 per minutew:{prefix}

The limits and the RateLimit headers

MCP

An assistant calls this as the tool report_show_airings, with the same input as one object. The MCP server
Request
# A new Idempotency-Key for every new request. Reuse it only to retry this same request.
IDEMPOTENCY_KEY=$(uuidgen)

curl -X POST 'https://affiliates.radioworkflow.com/api/v1/affiliations/srn-ksmt/weeks/2026-09-21/show-airings' \
  -H "Authorization: Bearer $AFFILIATE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{
  "epoch": 1,
  "version": 3,
  "items": [
    {
      "vehicle_id": "show-wd",
      "date": "2026-09-23",
      "rev": 1,
      "status": "carried",
      "start": "19:00",
      "end": "23:59",
      "unedited": true
    }
  ]
}'
Request body
{
  "epoch": 1,
  "version": 3,
  "items": [
    {
      "vehicle_id": "show-wd",
      "date": "2026-09-23",
      "rev": 1,
      "status": "carried",
      "start": "19:00",
      "end": "23:59",
      "unedited": true
    }
  ]
}
Response200
{
  "saved": [
    {
      "key": "srn-ksmt:show-wd:2026-09-23",
      "showId": "show-wd",
      "date": "2026-09-23",
      "status": "carried",
      "start": 1140,
      "end": 1439,
      "unedited": true,
      "source": "api",
      "airedDate": "2026-09-23",
      "rev": 2
    }
  ],
  "errors": [],
  "week": {
    "state": "in_progress",
    "epoch": 1,
    "rev": 2
  }
}

Try it

Demo data, no key, nothing saved