Falcon Rundown Gateway API Falcon Rundown

Base URL: https://gateway.wearefalcon.tv
Format: MOS XML for reads, JSON for triggers, MOS XML for asset import
Primary source: Falcon Rundown gateway routes (rundown/mos/v1, project/published/v1, triggers, assets)

Overview

The Falcon Rundown Gateway is the public surface that lets external systems consume Falcon Rundown data and push state back into it. It is used by prompter systems, playout automation, Falcon Play, MOS-compatible clients, and custom integrations. The gateway is organised around four endpoint families: read a rundown as MOS XML, discover all rundowns published from a project, push on-air state from automation back into the rundown, and import assets discovered by Falcon Play (cameras, video clips, graphic templates, automation functions) into a project's asset package.

Live production warning. The triggers endpoint and the asset import endpoint can change what prompters and operator dashboards display immediately. Test integrations against a non-live project first, confirm the rundown token belongs to the show you intend to drive, and avoid sending repeated commands unless the integration is intentionally designed to do so.

Base URL and request format

All gateway routes are served from the gateway.wearefalcon.tv host. Always use https://.

https://gateway.wearefalcon.tv/rundown/mos/v1/{rundownToken}
https://gateway.wearefalcon.tv/project/published/v1/{projectToken}
https://gateway.wearefalcon.tv/triggers/{rundownToken}
https://gateway.wearefalcon.tv/assets/

Tokens are Base64-encoded and may contain +, / and = characters. URL-encode the token segment once before sending it.

const url =
  'https://gateway.wearefalcon.tv/rundown/mos/v1/'
  + encodeURIComponent(rundownToken);

POST endpoints expect Content-Type: application/json (triggers) or Content-Type: application/xml (asset import). CORS is enabled with Access-Control-Allow-Origin: * on the POST endpoints, and the asset import endpoint advertises X-Falcon-ProjectID, X-Falcon-AssetKind, and X-Falcon-Sync-Mode as allowed request headers so browser-based controllers on a trusted network can call them directly.

Authentication and network safety

The gateway does not use Bearer tokens. Access is controlled by opaque, encrypted resource tokens that are minted inside Falcon Rundown and shared with integrators.

  • A rundown token identifies one rundown. It is generated from the numeric rundown ID using AES-128-ECB and Base64-encoded. The same token is used by the MOS endpoint and the triggers endpoint.
  • A project token identifies one project and is exposed in the project's Publish Settings dialog. It is used by the published-catalog endpoint.
  • An asset package keytoken identifies which project's asset package an import is being delivered to. It is sent in the X-Falcon-ProjectID header (or ?projectId= query parameter) on the asset import endpoint.
Treat tokens like passwords. Anyone holding a rundown token can read the rundown and update its on-air state via the triggers endpoint. Anyone holding a project token can enumerate every published rundown in that project. Numeric rundown or project IDs must never appear in URLs — only the encrypted token form is accepted.

Common response model

XML endpoints return application/xml; charset=utf-8. JSON endpoints return application/json; charset=utf-8 with a top-level ok flag where applicable. Error responses are typically {"error": "..."} (project catalog) or {"ok": false, "error": "..."} (triggers and asset import).

StatusTypical meaning
200Success. Body contains the requested resource or operation result.
204CORS preflight response (no body).
400Invalid token, malformed payload, missing required field, or unsupported asset type.
404Rundown, project, or asset package not found, or the request path does not match any gateway route.
405Wrong HTTP verb (for example POST on a GET-only route).
429Rate limit exceeded. Honour the Retry-After response header.
500Server-side error while executing the request.

Endpoint summary

AreaEndpointPurpose
Rundown MOSGET /rundown/mos/v1/{rundownToken}Return one rundown including stories, items, prompter text, and story comments as MOS XML.
Rundown MOSGET /rundown/mos/v1/{rundownToken}?debug=1Return the raw rundown / stories data as JSON for debugging.
Project catalogGET /project/published/v1/{projectToken}List the encrypted rundown tokens currently published from a project.
TriggersPOST /triggers/{rundownToken}Update the on-air flag, current story, and current timecode for a rundown.
Asset importPOST /assets/Replace (or merge) a project's asset package with a MOS payload of CAM, SERVER, GRAPHIC, or FUNCTION assets, including tags and free-form metadata.

Rundown MOS endpoint

The MOS endpoint is the read interface every prompter, MOS client, or external rundown viewer should call. It returns one full rundown — stories, items, item variables, prompter text, and story comments — in a MOS-style XML envelope. It is rate-limited and cache-aware.

Fetch a rundown as MOS XML

GET/rundown/mos/v1/{rundownToken}

The token segment must be URL-encoded. No request body is required.

Query parameterRequiredDescription
debugNoPass ?debug=1 to receive the rundown and stories as raw JSON instead of MOS XML. Useful when troubleshooting parser issues.

Response headers

HeaderDescription
Content-Typeapplication/xml; charset=utf-8, or application/json with ?debug=1.
X-Cache-StatusHIT when the response was served from the smart cache, MISS when it was just rebuilt from the database.
X-Cached-AtISO timestamp of when the cached payload was written (only present on HIT).
Retry-AfterSeconds the client must wait before retrying (only when rate-limited).

MOS XML response

<?xml version="1.0" encoding="UTF-8"?>
<mos>
  <mosVersion>2.8.5</mosVersion>
  <apiVersion>1.0.0</apiVersion>
  <ro>
    <roID>123</roID>
    <roSlug>Evening News</roSlug>
    <roProjectID>42</roProjectID>
    <roStartTime>2026-02-15 17:30:00</roStartTime>
    <roEndTime>2026-02-15 18:00:00</roEndTime>
    <story>
      <storyID>456</storyID>
      <storySlug>Lead Story</storySlug>
      <storySeq>1</storySeq>
      <storyPos>10</storyPos>
      <storyTime>00:00:45</storyTime>
      <storyVOTime>00:00:20</storyVOTime>
      <storyTotalTime>00:01:05</storyTotalTime>
      <item>
        <itemID>RDQ1XWH7LFZH5ON00WLB40</itemID>
        <itemType>cam</itemType>
        <itemSlug>CAM 1</itemSlug>
        <itemVars>
          <var name="voice-over" value="1" />
          <var name="input" value="SDI 1" />
        </itemVars>
        <itemPrompter>Good evening and welcome to the show.</itemPrompter>
      </item>
      <storyComments>
        <comment>
          <commentID>789</commentID>
          <commentUser>John Producer</commentUser>
          <commentBody>Remember to check audio levels</commentBody>
          <commentTime>2026-02-15 10:30:45</commentTime>
          <commentPrivate>false</commentPrivate>
        </comment>
      </storyComments>
    </story>
  </ro>
</mos>

Field reference

ElementDescription
mosVersionMOS protocol revision the gateway emits (currently 2.8.5).
apiVersionFalcon gateway revision (currently 1.0.0).
roRunning order container. One per response.
roID / roSlugNumeric rundown ID and human title.
roProjectIDNumeric project ID that owns the rundown.
roStartTime / roEndTimePlanned start and end datetime of the rundown.
storyOne story per rundown row, in playout order.
storyID / storySlugNumeric story ID and cleaned title.
storySeq / storyPosSequence and position used for sorting.
storyTime / storyVOTime / storyTotalTimePlanned read time, voice-over time, and total story duration as HH:MM:SS.
itemOne production item parsed from the story body.
itemIDStable item identifier (the data-id from the editor, or a synthetic {storyId}_{n} fallback).
itemTypeOne of cam, server, graphic, function, sidenote.
itemSlugCleaned display name of the asset.
parentItemIDPresent on subitems and points at the primary item they belong to.
itemVarsContainer of <var name="..." value="..."/> attributes. Always present on cam items (which include voice-over=1) and on items that carry data-* attributes such as input or graphic template fields.
itemPrompterPrompter text accumulated from the story body between this item and the next primary item. Whitespace is normalised. Only primary items receive prompter text — subitems never do.
storyCommentsComments attached at story level. Deleted comments are filtered out. Each comment exposes commentID, commentUser, commentBody, commentTime, and commentPrivate.

Caching

The gateway uses a smart cache backed by the project's data_versions entries. Every read first checks the latest update timestamp for the rundown's project and compares it with the cached file's stored timestamp.

  • If the timestamps match, the response is served from the on-disk cache and X-Cache-Status: HIT is set.
  • If the project's data has changed, the rundown is rebuilt from the database, re-cached, and X-Cache-Status: MISS is set.
  • Publish, edit, archive, and comment activity invalidate the cache automatically on the next request.

Rate limiting

The MOS endpoint enforces a 3-second minimum interval per IP and session. Repeated requests inside that window get 429 Too Many Requests with a Retry-After header. Build clients that respect a polling interval of at least three seconds.

Project published catalog

The published catalog lets external systems discover every rundown that has been marked Published to Gateway inside one Falcon Rundown project, without ever exposing numeric IDs.

List rundowns published in a project

GET/project/published/v1/{projectToken}

The project token comes from Project › Publish Settings in Falcon Rundown. URL-encode it before use.

XML response

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Cache-Control: no-store

<?xml version="1.0" encoding="UTF-8"?>
<rundowns type="Project" projectTitle="Evening Shows">
  <rundown type="External">VWN5MUEzeStxT0tLNEFSMTJtbWlwQT09</rundown>
  <rundown type="External">djJ6WCsyZklmTmMvQWRrcFA5Q05Xdz09</rundown>
</rundowns>
  • <rundowns> always carries type="Project" and the XML-escaped projectTitle attribute.
  • Each <rundown> element contains an encrypted rundown token that can be fed directly into the MOS endpoint.
  • Archived rundowns and rundowns that are not flagged gateway_published are excluded.
  • An existing project with no published rundowns still returns 200 OK and an empty <rundowns> container.

Error responses

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8

{"error":"project_not_found"}
HTTP/1.1 405 Method Not Allowed
Allow: GET

{"error":"method_not_allowed"}
HTTP/1.1 429 Too Many Requests
Retry-After: 60

{"error":"too_many_requests"}
HTTP/1.1 500 Internal Server Error

{"error":"internal_error"}

Failed-token attempts (invalid or unknown project tokens) are rate-limited to 10 attempts per 60 seconds per client to protect against token enumeration.

Triggers endpoint

The triggers endpoint is how playout, automation, or a Falcon Play instance pushes on-air state back into a rundown so that prompters can highlight the active story and timecode.

Update on-air state

POST/triggers/{rundownToken}

The rundown token is the same encrypted token used by the MOS endpoint. URL-encode it before sending. The path /trigger/{token} (singular) is also accepted.

FieldTypeRequiredDescription
on_air_flagintegerYes1 when the rundown is live, 0 when it is off-air. Any other value returns 400.
on_air_story_idintegerNoNumeric story ID currently on air. Ignored when on_air_flag = 0 (the gateway clears it).
on_air_timestringNoCurrent timecode as HH:MM:SS. Ignored when on_air_flag = 0.
{
  "on_air_flag": 1,
  "on_air_story_id": 456,
  "on_air_time": "20:59:43"
}
{
  "ok": true,
  "rundown_id": 123,
  "rundown_title": "Evening News",
  "updated": {
    "on_air_flag": 1,
    "on_air_story_id": 456,
    "on_air_time": "20:59:43"
  }
}

Error responses use {"ok": false, "error": "..."} and the matching status code (400, 404, 405, or 500).

Live impact. Setting on_air_flag = 1 causes connected prompters and dashboards to switch their visual indicators immediately. Always confirm the rundown token belongs to the show you intend to drive.

The triggers endpoint advertises Access-Control-Allow-Origin: * and supports the OPTIONS preflight (returns 204 No Content) so browser-based controllers on a trusted network can call it directly.

Asset import endpoint

The asset import endpoint accepts a MOS XML payload describing one batch of assets and reconciles the project's asset package with it. It is the entry point Falcon Play and other delivery centrals use to register cameras, video files, graphic templates, and automation functions, along with their tags and dynamic metadata.

Replace is the default. The incoming payload is treated as the authoritative full export for the given {package, type} pair. Any asset of that type that already exists in the package but is not present in the payload will be deleted, so source-side deletions propagate automatically. Use X-Falcon-Sync-Mode: merge (or ?syncMode=merge) to switch back to the legacy upsert-only behaviour.

Import a batch of assets

POST/assets/
SourceHeader / queryDescription
Project packageX-Falcon-ProjectID header, or ?projectId= queryThe keytoken value of the asset_packages row to import into. Required.
Asset kindX-Falcon-AssetKind header, or ?kind= queryOverrides the type attribute on <falconAssets>. Optional.
Asset kind (XML)<falconAssets type="...">Used when no header or query override is supplied.
Sync modeX-Falcon-Sync-Mode header, or ?syncMode= queryreplace (default) prunes assets of the given type that are missing from the payload. merge only upserts and never deletes.
Allow empty wipe?allowEmpty=1 query, or <falconAssets allowEmpty="true">Required confirmation when sending an empty payload in replace mode. Without it, an empty payload is refused with 400 to protect against accidental wipes.

Accepted asset kinds are CAM, SERVER, GRAPHIC, and FUNCTION. The synonyms VIDEO → SERVER, INPUT → CAM, and FUNC / FUNCTIONS → FUNCTION are normalised automatically.

Replace pruning is always scoped to package_id + type. A CAM import never touches GRAPHIC rows, and vice versa, so each Falcon Play delivery central can keep updating one asset kind without disturbing the others.

Example payload — CAM with DVE inputs

POST /assets/
Content-Type: application/xml
X-Falcon-ProjectID: 1148bbcf46f056a4e74ea16f739893
X-Falcon-AssetKind: CAM

<mos>
  <mosPayload>
    <falconAssets type="CAM">
      <asset>
        <name>CAM 1</name>
        <description>Studio camera 1</description>
        <input>1</input>
        <subtype>Camera</subtype>
        <showInInputDropdowns>true</showInInputDropdowns>
        <keyinputs_preview>
          <input>CAM 2</input>
          <input>CAM 3</input>
          <input></input>
          <input>CAM 5</input>
        </keyinputs_preview>
      </asset>
    </falconAssets>
  </mosPayload>
</mos>

Example payload — SERVER (video clip) with tags and metadata

POST /assets/
Content-Type: application/xml
X-Falcon-ProjectID: 1148bbcf46f056a4e74ea16f739893
X-Falcon-AssetKind: SERVER

<mos>
  <mosPayload>
    <falconAssets type="SERVER">
      <asset>
        <name>VT Opening Titles</name>
        <description>Show opener with music bed</description>
        <sourceSystem>falcon-play</sourceSystem>
        <fileName>vt-opening-titles.mp4</fileName>
        <path>/media/news/2026-06-14/vt-opening-titles.mp4</path>
        <thumbnail>https://media.example.com/thumbs/vt-opening-titles.jpg</thumbnail>
        <duration>00:00:24.12</duration>
        <resolution>1920x1080</resolution>
        <codec>h264</codec>
        <fps>50</fps>
        <tags>
          <tag>Opener</tag>
          <tag>News</tag>
          <tag>Music Bed</tag>
        </tags>
        <metadata>
          <field key="archive_id"   value="VT-2026-0142"/>
          <field key="rights"       value="cleared"/>
          <field key="created_by">Edit Suite 3</field>
        </metadata>
        <metadataJson><![CDATA[
          {"source":"falcon-play","clip":{"id":"VT-2026-0142","loudness":-23.0},"audio":{"tracks":2,"language":"da"}}
        ]]></metadataJson>
      </asset>
    </falconAssets>
  </mosPayload>
</mos>

Example payload — GRAPHIC with tags and metadata

POST /assets/
Content-Type: application/xml
X-Falcon-ProjectID: 1148bbcf46f056a4e74ea16f739893
X-Falcon-AssetKind: GRAPHIC

<mos>
  <mosPayload>
    <falconAssets type="GRAPHIC">
      <asset>
        <name>Lower Third - Host</name>
        <description>Lower third for host introduction</description>
        <fileName>lower-third-host.html</fileName>
        <tags>
          <tag>News</tag>
          <tag>Lower Third</tag>
          <tag>Studio A</tag>
        </tags>
        <metadata>
          <field key="location"   value="Studio 2"/>
          <field key="created_by" value="Jane Producer"/>
          <field key="version">3</field>
        </metadata>
        <metadataJson><![CDATA[
          {"source":"archive","template":{"id":42,"name":"lt-host"},"people":["Anna","Bo"]}
        ]]></metadataJson>
        <variables>
          <var key="name"  label="Name"  type="string" required="true" gddType="text"/>
          <var key="title" label="Title" type="string" default="Host"/>
        </variables>
      </asset>
    </falconAssets>
  </mosPayload>
</mos>

Tags

  • Stored first-class in asset_tags (one row per unique tag inside the package) and linked through asset_tag_map, so they can be used for search and faceting later.
  • Names are case-insensitively deduplicated using a normalised form, but the original casing is preserved for display.
  • Three input shapes are accepted: child elements <tag>News</tag>, attribute form <tag name="News"/>, and comma/semicolon-separated text content inside <tags>.
  • On every import the asset's tag links are rebuilt from the payload. In replace mode, package-level tags that no longer have any asset references are removed automatically.
  • A safety cap of 200 tags per asset is applied.

Dynamic metadata

Two complementary metadata transports are accepted — both optional, both forward compatible.

BlockStoragePurpose
<metadata><field key="..." value="..."/> (flattened)asset_metadata table (one row per key)Deterministic, indexable, search-friendly key/value pairs.
<metadataJson> (raw JSON, often inside CDATA)Inside assets.source_payload under metadataJsonLossless full metadata blob for downstream rehydration and AI processing.
  • <metadata> accepts <field key="k" value="v"/>, <field key="k">v</field>, and <meta key="k" value="v"/>. Element-name keys (e.g. <location>Studio 2</location>) are also accepted when no explicit key attribute is present.
  • Keys beginning with _ are treated as internal/private and silently ignored.
  • A safety cap of 500 entries per asset is enforced.
  • When only <metadataJson> is provided, the importer derives a flat key list from it automatically (nested objects become dotted keys, arrays use bracket indices). When both are present, the explicit <metadata> block wins for the indexable rows; <metadataJson> is always preserved as-is.
  • Tags, the flat metadata map, and the original metadataJson are also mirrored into assets.source_payload under tags, metadata, and metadataJson for clients that read the JSON blob directly.

Upsert and replace behaviour

  • CAM, SERVER, and GRAPHIC assets are matched by name inside the package. An existing row with the same name is updated; otherwise a new row is inserted.
  • FUNCTION assets are matched by uid, which allows multiple functions to share the same display name as long as their UIDs differ.
  • For every imported asset the previous asset_variables, asset_metadata, and tag links are deleted and rebuilt from the payload. There is no partial-merge of those collections — always send the full list.
  • In replace mode, after the upsert loop completes the gateway deletes any asset of the same type in the package that was not seen in the payload. asset_variables, asset_metadata, and tag-map rows for those assets cascade away through foreign keys.
  • GRAPHIC assets accept a <variables><var ...> block. Each var may carry key, label, type, default, required, min, max, step, placeholder, gddType, and a nested <options><option value="..." label="..."/></options> list for choice-style fields.
  • CAM assets accept a <keyinputs_preview><input> list describing DVE or SuperSource inputs. Empty entries are preserved — position matters because each entry becomes a numbered variable (input1, input2, …) with gdd_type=input_dropdown.

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "ok": true,
  "message": "Imported assets successfully",
  "syncMode": "replace",
  "receivedCount": 2,
  "created": 1,
  "updated": 1,
  "deleted": 1,
  "projectId": "1148bbcf46f056a4e74ea16f739893",
  "packageId": 17,
  "type": "GRAPHIC",
  "tagsCreated": 2,
  "tagsLinked": 4,
  "metadataPairs": 3,
  "dveInputsProcessed": 0
}
FieldDescription
syncModeEcho of the resolved sync mode (replace or merge).
receivedCountNumber of <asset> children the parser found in the payload.
created / updatedHow many assets rows were inserted or updated.
deletedHow many existing assets of the same type were pruned because they were missing from the payload (always 0 in merge mode).
packageIdNumeric asset_packages.id the import was applied to.
typeThe resolved asset kind after header / XML normalisation.
tagsCreatedNew rows added to asset_tags for this package during the import.
tagsLinkedTotal number of asset-to-tag links inserted (deduplicated per asset).
metadataPairsNumber of flat asset_metadata rows written across all imported assets.
dveInputsProcessedTotal DVE or SuperSource entries inserted as input1…inputN variables.

Append ?debug=1 to receive additional diagnostic details in a debug object on both success and error responses.

Error responses

StatusJSON bodyReason
400{"ok":false,"error":"Body er tom (forventer MOS XML)"}Empty request body.
400{"ok":false,"error":"Ugyldigt XML","details":[...]}The XML failed to parse. details contains libxml messages.
400{"ok":false,"error":"Root element skal v\u00e6re <mos>"}The payload is XML but the root element is not <mos>.
400{"ok":false,"error":"No <falconAssets> node found"}The MOS envelope is missing the Falcon Assets payload.
400{"ok":false,"error":"Mangler ProjectID ..."}Neither X-Falcon-ProjectID nor ?projectId= was provided.
400{"ok":false,"error":"Invalid X-Falcon-Sync-Mode ..."}The sync mode is not replace or merge.
400{"ok":false,"error":"Refusing to wipe assets ..."}Replace mode received zero assets without allowEmpty. Confirm with ?allowEmpty=1 or <falconAssets allowEmpty="true">.
400{"ok":false,"error":"Unsupported asset type","type":"..."}The resolved asset type is not CAM, SERVER, GRAPHIC, or FUNCTION.
404{"ok":false,"error":"Unknown ProjectID (keytoken)"}No asset_packages row matches the supplied keytoken.
405{"ok":false,"error":"Kun POST er tilladt"}Wrong HTTP verb.
500{"ok":false,"error":"DB import failed"}Database transaction was rolled back. Use ?debug=1 for the underlying error.
  1. Obtain the project token from Project › Publish Settings.
  2. Call GET /project/published/v1/{projectToken} to discover the rundown tokens currently published.
  3. For each rundown token of interest, call GET /rundown/mos/v1/{rundownToken} at most once every three seconds. Respect X-Cache-Status and Retry-After.
  4. Compare the returned roID, storyID, and itemID values with your local cache and update accordingly.
  5. When automation goes live, POST the on-air state to /triggers/{rundownToken} so prompters and dashboards reflect the current story and timecode.
  6. When new cameras, clips, graphics, or functions appear in Falcon Play, push them to POST /assets/ with the matching project keytoken.

Common examples

List rundowns published in a project

curl "https://gateway.wearefalcon.tv/project/published/v1/$PROJECT_TOKEN"

Fetch one rundown as MOS XML

curl "https://gateway.wearefalcon.tv/rundown/mos/v1/$RUNDOWN_TOKEN"

Inspect the raw rundown data

curl "https://gateway.wearefalcon.tv/rundown/mos/v1/$RUNDOWN_TOKEN?debug=1"

Take a story on air

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"on_air_flag":1,"on_air_story_id":456,"on_air_time":"20:59:43"}' \
  "https://gateway.wearefalcon.tv/triggers/$RUNDOWN_TOKEN"

Clear on-air state

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"on_air_flag":0}' \
  "https://gateway.wearefalcon.tv/triggers/$RUNDOWN_TOKEN"

Import a CAM batch from Falcon Play (replace mode)

curl -X POST \
  -H "Content-Type: application/xml" \
  -H "X-Falcon-ProjectID: 1148bbcf46f056a4e74ea16f739893" \
  -H "X-Falcon-AssetKind: CAM" \
  -H "X-Falcon-Sync-Mode: replace" \
  --data-binary @cameras.mos.xml \
  https://gateway.wearefalcon.tv/assets/

Add or update a single GRAPHIC without deleting siblings (merge mode)

curl -X POST \
  -H "Content-Type: application/xml" \
  -H "X-Falcon-ProjectID: 1148bbcf46f056a4e74ea16f739893" \
  -H "X-Falcon-AssetKind: GRAPHIC" \
  -H "X-Falcon-Sync-Mode: merge" \
  --data-binary @new-lower-third.mos.xml \
  https://gateway.wearefalcon.tv/assets/

JavaScript: discover rundowns and stream MOS XML

async function getPublishedRundownTokens(projectToken) {
  const url =
    'https://gateway.wearefalcon.tv/project/published/v1/'
    + encodeURIComponent(projectToken);

  const response = await fetch(url, { cache: 'no-store' });
  if (!response.ok) throw new Error(`Gateway HTTP ${response.status}`);

  const xml = new DOMParser().parseFromString(
    await response.text(),
    'application/xml'
  );

  return Array.from(xml.querySelectorAll('rundowns > rundown'))
    .map(el => el.textContent?.trim())
    .filter(Boolean);
}

async function getRundownMos(rundownToken) {
  const url =
    'https://gateway.wearefalcon.tv/rundown/mos/v1/'
    + encodeURIComponent(rundownToken);

  const response = await fetch(url);
  if (response.status === 429) {
    const retry = Number(response.headers.get('Retry-After') ?? 3);
    await new Promise(r => setTimeout(r, retry * 1000));
    return getRundownMos(rundownToken);
  }
  if (!response.ok) throw new Error(`Gateway HTTP ${response.status}`);
  return response.text();
}

Troubleshooting

SymptomLikely causeWhat to do
400 Invalid token on the MOS endpointThe token is not valid Base64 / AES-128-ECB, or it does not decrypt to a numeric rundown ID.Re-copy the token from Falcon Rundown and make sure it is URL-encoded exactly once.
404 Rundown not foundThe decrypted ID does not match any row in rundowns.Verify the rundown still exists and has not been hard-deleted.
404 project_not_foundThe project token did not decrypt to an existing project, or the failed-token rate limit was triggered.Verify the token is current and back off for 60 seconds before retrying.
429 Too many requestsPolling the MOS endpoint faster than once every three seconds, or more than 10 failed catalog attempts in a minute.Honour Retry-After and slow down the polling loop.
Duplicate prompter textOld client of the parser before the January 2026 fix.Read from the gateway, not a cached copy. The gateway parser already deduplicates child spans.
Stale rundown dataAn upstream proxy is caching the response.The gateway already controls caching with X-Cache-Status. Disable proxy-level caching or honour the gateway's own freshness signals.
Asset import returns 404 Unknown ProjectIDThe X-Falcon-ProjectID value does not match any asset_packages.keytoken.Confirm the keytoken in the Falcon Rundown asset package settings.
Asset import succeeds but variables are goneThe endpoint replaces all asset_variables for the asset on every import.Always send the complete variable list — never a partial update.
Assets disappeared after a successful importThe default sync mode is replace: any asset of the same type that is missing from the payload is pruned.Send the full authoritative list, or switch to X-Falcon-Sync-Mode: merge when you only want to upsert.
400 Refusing to wipe assetsAn empty payload was sent in replace mode without the safety opt-in.Confirm the wipe with ?allowEmpty=1 or <falconAssets allowEmpty="true">, or send a non-empty payload.
CORS preflight failsThe browser sent custom headers the gateway does not advertise.Use only the documented headers: Content-Type, X-Falcon-ProjectID, X-Falcon-AssetKind, X-Falcon-Sync-Mode, Authorization.

Versioning

  • The MOS endpoint reports its version via <mosVersion> (MOS protocol revision) and <apiVersion> (Falcon gateway revision).
  • Backwards-incompatible changes will live under a new versioned path segment (v2, v3…).
  • Additive fields (new itemType values, new variables, new comment fields) can appear at any time. Clients should ignore unknown elements gracefully.