PLATFORM GUIDE

Build on the live event stream.

Use the implemented guides and canonical OpenAPI contract for tenant-scoped publishing, live delivery, recovery and distribution.

01

Start with a match

Create a tenant-scoped fixture, start its canonical timeline and publish idempotent events.

02

Read public state

Retrieve the match, calculated score and cursor-paginated timeline with cache-aware responses.

03

Subscribe live

Use SSE and Last-Event-ID to reconnect to committed events without polling.

04

Verify webhooks

Validate the timestamp and HMAC signature before parsing or acting on a delivery.

05

Place an embed

Choose hosted match, iframe, JavaScript, score, results-centre or OBS outputs with revocable keys.

06

Integrate GAABlogs

Map tenant membership, public feeds, output keys and the authenticated migration bridge.

OPENAPI 3.1

API reference

Search all implemented versioned endpoints. Expand an operation for authentication, parameters, request shape and documented responses.

HTTP method

Showing 96 of 96 operations

post/auth/mobile/loginAuthenticate a verified account for organisation-scoped mobile publishing
Operation ID
createMobileSession
Authentication
Public or capability URL

Request schema

{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "email",
    "password"
  ],
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "password": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
    }
  }
}

Responses

  • 200Opaque revocable session token
  • 401Enumeration-safe invalid
  • 429Durable credential-attempt rate limit exceeded
post/auth/mobile/logoutRevoke the current mobile device session
Operation ID
revokeMobileSession
Authentication
Secure browser session

Responses

  • 200Session revoked
  • 401Missing or malformed mobile session
  • 429Logout rate limit exceeded
post/auth/mobile/logout-othersRevoke every other session owned by the mobile account
Operation ID
revokeOtherMobileSessions
Authentication
Secure browser session

Responses

  • 200Other device sessions revoked
  • 401Missing
  • 429Session-change rate limit exceeded
post/auth/mobile/refreshExtend a valid mobile session within its bounded 90-day lifetime
Operation ID
refreshMobileSession
Authentication
Secure browser session

Responses

  • 200Refreshed expiry without returning or rotating the opaque token
  • 401Missing
  • 429Daily refresh rate limit exceeded
post/auth/mobile/invitations/acceptAccept a contributor invitation using the invited verified mobile account
Operation ID
acceptMobileContributorInvitation
Authentication
Secure browser session

Request schema

{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "token"
  ],
  "properties": {
    "token": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{43}$"
    }
  }
}

Responses

  • 200Invitation accepted and current memberships refreshed
  • 400Invitation invalid
  • 401Missing
  • 403Signed-in account does not match the invited email
  • 429Invitation attempt rate limit exceeded
get/auth/sessionGet the authenticated browser user and organisation memberships
Operation ID
getBrowserSession
Authentication
Secure browser session

Responses

  • 200Current verified browser session
  • 401Missing
get/reader/preferencesList the mobile account's follows and bookmarks for currently public live stories
Operation ID
listReaderStoryPreferences
Authentication
Secure browser session

Responses

  • 200Current public story preferences
  • 401Missing
put/reader/preferencesAtomically replace follow and bookmark state for a public live story
Operation ID
replaceReaderStoryPreference
Authentication
Secure browser session

Request schema

{
  "$ref": "#/components/schemas/ReaderStoryPreferenceWrite"
}

Responses

  • 200Updated preference
  • 401Missing
  • 404Live story is private
  • 422Invalid preference input
  • 429Preference mutation rate limit exceeded
get/auth/sessionsList active browser sessions owned by the authenticated account
Operation ID
listBrowserSessions
Authentication
Secure browser session

Responses

  • 200Token-free device session list with current-device marker
  • 401Valid verified browser session required
delete/auth/sessions/{sessionId}Idempotently revoke one session owned by the authenticated account
Operation ID
revokeBrowserSession
Authentication
Secure browser session

Parameters

  • sessionIdpath · required

Responses

  • 200Session revoked or already revoked; current-session cookie is cleared when applicable
  • 403Same-origin check failed
  • 404Session does not belong to the account or does not exist
  • 429Session-change rate limit exceeded
post/auth/sessions/revoke-othersRevoke every other active session while preserving the issuing browser
Operation ID
revokeOtherBrowserSessions
Authentication
Secure browser session

Responses

  • 200Other active sessions revoked and audited
  • 403Same-origin check failed
  • 429Session-change rate limit exceeded
get/auth/data-exportDownload the authenticated user’s portable account data as JSON

Excludes passwords, token and credential hashes, encrypted secrets, IP hashes, and other subscribers’ contact details.

Operation ID
downloadAccountData
Authentication
Secure browser session

Responses

  • 200Private non-storable JSON attachment containing subject-attributed account and publishing data
  • 401Valid verified browser session required
  • 429Fixed-window request allowance exhausted
get/organisationsList the API credential's tenant organisation
Operation ID
listOrganisations
Authentication
Bearer credential: organisation:read

Responses

  • 200Tenant-scoped organisation collection
  • 401Missing or invalid credential
  • 403Credential lacks `organisation:read`
post/organisationsCreate an isolated workspace owned by the authenticated browser user
Operation ID
createWorkspace
Authentication
Secure browser session

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2,
      "maxLength": 160
    }
  }
}

Responses

  • 200Exact idempotent replay returned the original workspace
  • 201Workspace
  • 401Verified browser session required
  • 403Same-origin check failed
  • 409Idempotency key was reused with different workspace input
  • 422Workspace name failed validation
  • 429Daily workspace creation limit exceeded
patch/organisations/{organisationId}Idempotently update versioned workspace identity and branding
Operation ID
updateOrganisation
Authentication
Bearer credential: organisation:write

Parameters

  • organisationIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current integer workspace version

Request schema

{
  "$ref": "#/components/schemas/WorkspaceSettingsWrite"
}

Responses

  • 200Workspace identity updated
  • 403Credential actor is not a current owner or administrator
  • 404Resource unavailable
  • 409Stale version
  • 428If-Match version required
get/organisations/{organisationId}/membershipsList users and roles in the credential's tenant
Operation ID
listMemberships
Authentication
Bearer credential: membership:read

Parameters

  • organisationIdpath · required

Responses

  • 200Tenant membership collection
  • 404Resource unavailable
post/organisations/{organisationId}/membershipsAdd an existing verified account to the organisation
Operation ID
addOrganisationMember
Authentication
Bearer credential: membership:write

Parameters

  • organisationIdpath · required

Request schema

{
  "$ref": "#/components/schemas/CreateMembership"
}

Responses

  • 201Membership created and audited
  • 403Actor lacks a current administrative role or an administrator attempted to grant owner
  • 404Organisation or verified account unavailable
  • 409Account is already a member
patch/organisations/{organisationId}/memberships/{userId}Change a member role while retaining at least one owner
Operation ID
updateOrganisationMember
Authentication
Bearer credential: membership:write

Parameters

  • organisationIdpath · required
  • userIdpath · required

Request schema

{
  "type": "object",
  "required": [
    "role"
  ],
  "additionalProperties": false,
  "properties": {
    "role": {
      "$ref": "#/components/schemas/MembershipRole"
    }
  }
}

Responses

  • 200Membership role updated or an identical role replayed
  • 403Administrative role
  • 404Resource unavailable
delete/organisations/{organisationId}/memberships/{userId}Remove a member while retaining at least one owner
Operation ID
removeOrganisationMember
Authentication
Bearer credential: membership:write

Parameters

  • organisationIdpath · required
  • userIdpath · required

Responses

  • 200Membership removed and audited
  • 403Administrative role
  • 404Resource unavailable
get/organisations/{organisationId}/invitationsList masked tenant membership invitations and status
Operation ID
listMembershipInvitations
Authentication
Bearer credential: membership:read

Parameters

  • organisationIdpath · required
  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated invitations with masked destinations
  • 404Resource unavailable
post/organisations/{organisationId}/invitationsCreate or safely reissue a seven-day membership invitation
Operation ID
createMembershipInvitation
Authentication
Bearer credential: membership:write

Parameters

  • organisationIdpath · required

Request schema

{
  "$ref": "#/components/schemas/CreateMembership"
}

Responses

  • 200Expired or revoked invitation reissued with a new capability
  • 201Invitation created and encrypted email queued
  • 403Actor lacks current authority or administrator attempted to invite an owner
  • 409Destination already belongs to the organisation
  • 429Invitation creation rate limit exceeded
delete/organisations/{organisationId}/invitations/{invitationId}Idempotently revoke a pending membership invitation
Operation ID
revokeMembershipInvitation
Authentication
Bearer credential: membership:write

Parameters

  • organisationIdpath · required
  • invitationIdpath · required

Responses

  • 200Invitation revoked
  • 403Actor cannot manage the invited role
  • 404Resource unavailable
  • 409Invitation has already been accepted
post/invitations/acceptAccept an invitation using the matching verified browser account

Requires the secure browser session cookie and a same-origin request. The capability alone cannot grant membership.

Operation ID
acceptMembershipInvitation
Authentication
Secure browser session

Request schema

{
  "$ref": "#/components/schemas/AcceptInvitation"
}

Responses

  • 200Membership granted
  • 400Invitation invalid
  • 401Matching verified browser session required
  • 403Session email does not match the encrypted invitation destination
  • 429Acceptance attempt rate limit exceeded
get/teamsList tenant teams using an opaque cursor
Operation ID
listTeams
Authentication
Bearer credential: team:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • queryquery
  • external_idquery

Responses

  • 200Filtered tenant team collection
  • 400Invalid request
post/teamsIdempotently create a tenant team
Operation ID
createTeam
Authentication
Bearer credential: team:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/TeamWrite"
}

Responses

  • 200Identical creation safely replayed
  • 201Team created
  • 403Credential or actor cannot administer teams
  • 409Idempotency or external-ID uniqueness conflict
  • 422Team data failed validation
get/teams/{teamId}Retrieve one tenant team
Operation ID
getTeam
Authentication
Bearer credential: team:read

Parameters

  • teamIdpath · required

Responses

  • 200Versioned team resource
  • 404Resource unavailable
put/teams/{teamId}Idempotently replace mutable team details
Operation ID
replaceTeam
Authentication
Bearer credential: team:write

Parameters

  • teamIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current integer team version

Request schema

{
  "$ref": "#/components/schemas/TeamWrite"
}

Responses

  • 200Team updated or identical command safely replayed
  • 403Credential or actor cannot administer teams
  • 404Resource unavailable
  • 409Stale version
  • 428If-Match version required
get/participantsList tenant participants or players using an opaque cursor
Operation ID
listParticipants
Authentication
Bearer credential: participant:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • team_idquery
  • queryquery
  • external_idquery

Responses

  • 200Filtered tenant participant collection
  • 400Invalid request
post/participantsIdempotently create a participant under a tenant team
Operation ID
createParticipant
Authentication
Bearer credential: participant:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/ParticipantWrite"
}

Responses

  • 200Identical creation safely replayed
  • 201Participant created
  • 403Credential or actor cannot administer participants
  • 404Team not found in the tenant
  • 409Idempotency or external-ID uniqueness conflict
  • 422Participant data failed validation
get/participants/{participantId}Retrieve one tenant participant
Operation ID
getParticipant
Authentication
Bearer credential: participant:read

Parameters

  • participantIdpath · required

Responses

  • 200Versioned participant resource
  • 404Resource unavailable
put/participants/{participantId}Idempotently replace mutable participant details
Operation ID
replaceParticipant
Authentication
Bearer credential: participant:write

Parameters

  • participantIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current integer participant version

Request schema

{
  "$ref": "#/components/schemas/ParticipantWrite"
}

Responses

  • 200Participant updated or identical command safely replayed
  • 403Credential or actor cannot administer participants
  • 404Resource unavailable
  • 409Stale version
  • 428If-Match version required
get/competitionsList tenant competitions using an opaque cursor
Operation ID
listCompetitions
Authentication
Bearer credential: competition:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Tenant competition collection
post/competitionsIdempotently create a tenant competition
Operation ID
createCompetition
Authentication
Bearer credential: competition:write

Parameters

  • Idempotency-Keyheader · required

Responses

  • 200Identical creation replayed
  • 201Competition created
  • 409Idempotency or uniqueness conflict
  • 429Fixed-window request allowance exhausted
get/seasonsList tenant seasons, optionally filtered by competition
Operation ID
listSeasons
Authentication
Bearer credential: competition:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • competition_idquery

Responses

  • 200Tenant season collection
post/seasonsIdempotently create a season under a tenant competition
Operation ID
createSeason
Authentication
Bearer credential: competition:write

Parameters

  • Idempotency-Keyheader · required

Responses

  • 200Identical creation replayed
  • 201Season created
  • 404Competition not found in the tenant
  • 429Fixed-window request allowance exhausted
get/venuesList tenant venues using an opaque cursor
Operation ID
listVenues
Authentication
Bearer credential: venue:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Tenant venue collection
post/venuesIdempotently create a tenant venue
Operation ID
createVenue
Authentication
Bearer credential: venue:write

Parameters

  • Idempotency-Keyheader · required

Responses

  • 200Identical creation replayed
  • 201Venue created
  • 409Idempotency or uniqueness conflict
  • 429Fixed-window request allowance exhausted
get/tagsList canonical tenant-owned tags
Operation ID
listTags
Authentication
Bearer credential: tag:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated tenant tag collection
post/tagsIdempotently create a canonical tenant tag
Operation ID
createTag
Authentication
Bearer credential: tag:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/TagWrite"
}

Responses

  • 200Identical creation safely replayed
  • 201Tag created with version 1
  • 403Actor cannot administer tags
  • 409Slug or idempotency conflict
get/tags/{tagId}Retrieve one tenant-owned tag
Operation ID
getTag
Authentication
Bearer credential: tag:read

Parameters

  • tagIdpath · required

    Tenant-scoped tag identifier

Responses

  • 200Current tag and version
  • 404Resource unavailable
put/tags/{tagId}Idempotently replace mutable tag details
Operation ID
replaceTag
Authentication
Bearer credential: tag:write

Parameters

  • tagIdpath · required

    Tenant-scoped tag identifier

  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current integer tag version

Request schema

{
  "$ref": "#/components/schemas/TagWrite"
}

Responses

  • 200Tag replaced or identical command safely replayed
  • 404Resource unavailable
  • 409Slug
  • 428If-Match version required
get/live-blogsList tenant standalone live blogs
Operation ID
listLiveBlogs
Authentication
Bearer credential: live_blog:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • statusquery

Responses

  • 200Cursor-paginated tenant live-blog collection
post/live-blogsIdempotently create a scheduled standalone live blog
Operation ID
createLiveBlog
Authentication
Bearer credential: live_blog:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/CreateLiveBlog"
}

Responses

  • 200Identical creation replayed
  • 201Live blog and immutable created event committed
  • 409Idempotency or tenant uniqueness conflict
  • 429Fixed-window request allowance exhausted
get/live-blogs/publicDiscover public non-archived live blogs without authentication
Operation ID
discoverPublicLiveBlogs
Authentication
Public or capability URL

Parameters

  • qquery

    Server-side title and description search

  • statusquery
  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated public cards without draft or contributor administration data
  • 400Invalid search
  • 429Fixed-window request allowance exhausted
get/live-blogs/{liveBlogId}Get a tenant live blog and ordered lifecycle history
Operation ID
getLiveBlog
Authentication
Bearer credential: live_blog:read

Parameters

  • liveBlogIdpath · required

    Tenant-scoped live-blog identifier

Responses

  • 200Live-blog aggregate and immutable lifecycle events
  • 404Resource unavailable
post/live-blogs/{liveBlogId}/eventsAppend a lifecycle transition using optimistic concurrency
Operation ID
transitionLiveBlog
Authentication
Bearer credential: live_blog:write

Parameters

  • liveBlogIdpath · required

    Tenant-scoped live-blog identifier

  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current aggregate version

Request schema

{
  "type": "object",
  "required": [
    "action"
  ],
  "additionalProperties": false,
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "start",
        "pause",
        "resume",
        "finish",
        "archive"
      ]
    },
    "occurred_at": {
      "type": "string",
      "format": "date-time"
    }
  }
}

Responses

  • 200Identical transition replayed
  • 201Lifecycle event appended and status projection updated
  • 409Version or idempotency conflict
  • 422Invalid lifecycle transition
  • 429Fixed-window request allowance exhausted
get/live-blogs/{liveBlogId}/publicGet the cache-friendly public live-blog read model
Operation ID
getPublicLiveBlog
Authentication
Public or capability URL

Parameters

  • liveBlogIdpath · required

    Tenant-scoped live-blog identifier

Responses

  • 200Public live-blog summary with aggregate version
  • 404Live blog is unavailable
  • 429Fixed-window request allowance exhausted
get/live-blogs/{liveBlogId}/timelineRead the public standalone timeline from the durable outbox
Operation ID
getPublicLiveBlogTimeline
Authentication
Public or capability URL

Parameters

  • liveBlogIdpath · required

    Tenant-scoped live-blog identifier

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • latestquery

    Return the newest bounded window in chronological order

  • beforequery

    Return the preceding chronological page before this aggregate version

  • event_idquery

    Return one public timeline event for a specific-update deep link; cannot be combined with cursors or latest

Responses

  • 200Cursor-paginated canonical public events
  • 404Live blog is unavailable
  • 429Fixed-window request allowance exhausted
get/live-blogs/{liveBlogId}/streamResume a public standalone timeline using Server-Sent Events
Operation ID
streamPublicLiveBlog
Authentication
Public or capability URL

Parameters

  • liveBlogIdpath · required

    Tenant-scoped live-blog identifier

  • Last-Event-IDheader

    Last applied aggregate version

Responses

  • 200SSE stream with stable aggregate-version IDs
  • 400Invalid request
  • 404Live blog is unavailable
  • 429Fixed-window request allowance exhausted
get/matchesList and filter tenant matches using an opaque cursor
Operation ID
listMatches
Authentication
Bearer credential: match:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • statusquery
  • competitionquery
  • team_idquery
  • date_fromquery
  • date_toquery

Responses

  • 200Filtered tenant match collection
  • 400Invalid request
post/matchesCreate a tenant match, teams, and initial output channels atomically
Operation ID
createMatch
Authentication
Bearer credential: match:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/CreateMatch"
}

Responses

  • 200Identical idempotent creation replayed
  • 201Match created once
  • 409Idempotency key reused with different match data
  • 422Invalid request
get/matches/{matchId}Get a public match and current scoreboard
Operation ID
getMatch
Authentication
Public or capability URL

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

Responses

  • 200Match
  • 404Resource unavailable
  • 429Fixed-window request allowance exhausted
get/matches/{matchId}/scoreGet a projected current scoreboard
Operation ID
getCurrentScore
Authentication
Public or capability URL

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

Responses

  • 200Current score projection
  • 404Resource unavailable
  • 429Fixed-window request allowance exhausted
post/matches/{matchId}/eventsAppend an immutable match event
Operation ID
appendMatchEvent
Authentication
Bearer credential: match:write

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current aggregate version

Request schema

{
  "$ref": "#/components/schemas/AppendMatchEvent"
}

Responses

  • 200Identical idempotent request replayed
  • 201Event appended and score projection committed
  • 401Missing
  • 403Credential lacks `match:write` scope
  • 409Version or idempotency conflict
  • 422Invalid request
  • 429Fixed-window request allowance exhausted
get/matches/{matchId}/timelineGet an ordered cursor-paginated match timeline
Operation ID
getMatchTimeline
Authentication
Public or capability URL

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

  • cursorquery

    Opaque cursor returned by the previous response

  • limitquery

Responses

  • 200Timeline page
  • 400Invalid request
  • 404Resource unavailable
get/matches/{matchId}/streamResume a public timeline using Server-Sent Events
Operation ID
streamMatchTimeline
Authentication
Public or capability URL

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

  • Last-Event-IDheader

    Last applied aggregate version

Responses

  • 200SSE stream with stable event IDs
  • 400Invalid request
  • 404Resource unavailable
get/storiesList tenant-published stories with optional match or live-blog filtering
Operation ID
listStories
Authentication
Bearer credential: story:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • match_idquery
  • live_blog_idquery
  • tagquery

    Stable tenant tag slug

Responses

  • 200Cursor-paginated sanitised published stories with author attribution
  • 400Invalid request
  • 401Missing or invalid credential
  • 403Credential lacks `story:read`
  • 404The filtered match is unavailable in this tenant
post/storiesPublish a sanitised story and canonical timeline event atomically
Operation ID
publishStory
Authentication
Bearer credential: story:write

Parameters

  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current match or live-blog aggregate version

Request schema

{
  "$ref": "#/components/schemas/PublishStory"
}

Responses

  • 200Identical idempotent request replayed
  • 201Story and story.published event committed
  • 404Resource unavailable
  • 409Aggregate version or idempotency-content conflict
  • 422Invalid request
  • 428If-Match aggregate version is required
  • 429Story publication rate limit exceeded
get/analyticsRetrieve bounded operational and editorial tenant analytics
Operation ID
getTenantAnalytics
Authentication
Bearer credential: analytics:read

Parameters

  • periodquery

    UTC reporting window in days

Responses

  • 200Canonical coverage
  • 400Period is not 7
  • 401Missing or invalid credential
  • 403Credential lacks `analytics:read`
  • 429Analytics read rate limit exceeded
get/audit-recordsList immutable tenant audit history with read-time metadata safety
Operation ID
listAuditRecords
Authentication
Bearer credential: audit:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • actionquery

    Exact action filter

  • resource_typequery

    Exact resource-type filter

  • actor_idquery
  • fromquery

    Inclusive creation boundary

  • toquery

    Exclusive creation boundary

Responses

  • 200Cursor-paginated records with actor attribution and recursively redacted metadata
  • 400Invalid cursor
  • 401Missing or invalid credential
  • 403Credential lacks `audit:read`
  • 429Audit read rate limit exceeded
get/stories/draftsList tenant editorial stories, optionally filtered to one live blog
Operation ID
listEditorialStories
Authentication
Bearer credential: story:read

Parameters

  • live_blog_idquery
  • limitquery

Responses

  • 200Current editorial story read models ordered by latest update
  • 400Invalid live-blog identifier
  • 401Missing or invalid credential
  • 403Credential lacks `story:read`
post/stories/draftsCreate a tenant-scoped sanitised story draft
Operation ID
createStoryDraft
Authentication
Bearer credential: story:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/PublishStory"
}

Responses

  • 200Identical idempotent request replayed
  • 201Draft and immutable created revision committed
  • 403Current actor lacks an editorial role
  • 404Match or live-blog target unavailable in this tenant
  • 409Idempotency-content conflict
  • 422Invalid request
  • 429Editorial write rate limit exceeded
get/stories/{storyId}Retrieve a tenant story and its complete revision history for preview
Operation ID
getEditorialStory
Authentication
Bearer credential: story:read

Parameters

  • storyIdpath · required

Responses

  • 200Current story plus ordered immutable revisions
  • 404Resource unavailable
patch/stories/{storyId}Edit a draft with optimistic concurrency; editing a scheduled story returns it to draft
Operation ID
updateStoryDraft
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "body_html"
  ],
  "additionalProperties": false,
  "properties": {
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "body_html": {
      "type": "string",
      "maxLength": 100000
    }
  }
}

Responses

  • 200Draft updated or identical command replayed
  • 409Story state
  • 422Invalid request
  • 428If-Match story version is required
post/stories/{storyId}/schedulePersist a future publication time and immutable scheduled revision
Operation ID
scheduleStory
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "scheduled_at"
  ],
  "additionalProperties": false,
  "properties": {
    "scheduled_at": {
      "type": "string",
      "format": "date-time"
    }
  }
}

Responses

  • 200Future schedule persisted or identical command replayed
  • 409Story state
  • 422Invalid or non-future publication time
  • 428If-Match story version is required
put/stories/{storyId}/tagsAtomically replace a story's canonical tenant tags
Operation ID
replaceStoryTags
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "tag_ids"
  ],
  "additionalProperties": false,
  "properties": {
    "tag_ids": {
      "type": "array",
      "maxItems": 20,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "format": "uuid"
      }
    }
  }
}

Responses

  • 200Current story with ordered tags; exact commands replay safely
  • 403Current actor lacks editorial access to this story
  • 404Resource unavailable
  • 409Story version or idempotency conflict
  • 422A supplied tag is invalid or belongs to another tenant
  • 428If-Match story version is required
post/stories/{storyId}/publishPublish an existing draft into its canonical match or live-blog timeline transaction
Operation ID
publishStoryDraft
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "aggregate_version"
  ],
  "additionalProperties": false,
  "properties": {
    "aggregate_version": {
      "type": "integer",
      "minimum": 0
    }
  }
}

Responses

  • 200Existing draft published
  • 409Story/aggregate version
  • 428If-Match story version is required
post/stories/{storyId}/submitSubmit the current story revision for editorial review
Operation ID
submitStoryForReview
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Responses

  • 200Story moved to pending review with an immutable submitted revision
  • 403Current actor lacks an editorial role
  • 409Story state
  • 428If-Match story version is required
post/stories/{storyId}/reviewApprove a pending story or request contributor changes
Operation ID
reviewStory
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "decision"
  ],
  "additionalProperties": false,
  "properties": {
    "decision": {
      "type": "string",
      "enum": [
        "approve",
        "request_changes"
      ]
    },
    "reason": {
      "type": "string",
      "minLength": 3,
      "maxLength": 1000
    }
  }
}

Responses

  • 200Immutable moderation decision and audit record committed
  • 403Only an owner
  • 409Story state
  • 422A change request requires a reason
  • 428If-Match story version is required
post/stories/{storyId}/correctionsCorrect a published story while preserving prior content and emitting correction.created
Operation ID
correctPublishedStory
Authentication
Bearer credential: story:write

Parameters

  • storyIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current story revision version

Request schema

{
  "type": "object",
  "required": [
    "aggregate_version",
    "body_html",
    "reason"
  ],
  "additionalProperties": false,
  "properties": {
    "aggregate_version": {
      "type": "integer",
      "minimum": 0
    },
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "body_html": {
      "type": "string",
      "maxLength": 100000
    },
    "reason": {
      "type": "string",
      "minLength": 3,
      "maxLength": 1000
    }
  }
}

Responses

  • 200Corrected read model
  • 409Story/aggregate version
  • 422Invalid request
  • 428If-Match story version is required
get/subscriptionsList masked tenant subscribers and their topic rules
Operation ID
listSubscribers
Authentication
Bearer credential: subscription:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated subscriber metadata without contact addresses
  • 401Missing or invalid credential
  • 403Credential lacks `subscription:read`
post/subscriptionsRecord consent and queue double-opt-in verification
Operation ID
createSubscription
Authentication
Bearer credential: subscription:write

Parameters

  • Idempotency-Keyheader · required

Request schema

{
  "$ref": "#/components/schemas/CreateSubscription"
}

Responses

  • 200Exact idempotent request replayed without another email
  • 202Pending subscriber stored and verification email queued
  • 409Destination already exists or idempotency-content conflict
  • 422Invalid request
  • 429Subscription creation rate limit exceeded
put/subscriptions/{subscriberId}Atomically replace an active subscriber's topic and event rules
Operation ID
replaceSubscriberNotificationRules
Authentication
Bearer credential: subscription:write

Parameters

  • subscriberIdpath · required
  • Idempotency-Keyheader · required
  • If-Matchheader · required

    Current subscriber rule version

Request schema

{
  "type": "object",
  "required": [
    "topics"
  ],
  "additionalProperties": false,
  "properties": {
    "topics": {
      "type": "array",
      "minItems": 1,
      "maxItems": 20,
      "uniqueItems": true,
      "items": {
        "$ref": "#/components/schemas/SubscriptionTopic"
      }
    }
  }
}

Responses

  • 200Replaced rule set
  • 403Actor is not a current owner or administrator
  • 404Resource unavailable
  • 409Version or idempotency conflict
  • 422Invalid topic
  • 428If-Match subscriber version is required
  • 429Notification rule change rate limit exceeded
delete/subscriptions/{subscriberId}Idempotently unsubscribe and deactivate all topic rules
Operation ID
unsubscribeSubscriber
Authentication
Bearer credential: subscription:write

Parameters

  • subscriberIdpath · required

Responses

  • 200Subscriber suppression state and timestamp
  • 404Resource unavailable
post/subscriptions/verifyActivate a pending subscription with a single-use capability token
Operation ID
verifySubscription
Authentication
Public or capability URL

Request schema

{
  "type": "object",
  "required": [
    "token"
  ],
  "additionalProperties": false,
  "properties": {
    "token": {
      "type": "string",
      "minLength": 43,
      "maxLength": 43
    }
  }
}

Responses

  • 200Subscriber and topic rules activated
  • 400Token invalid
  • 429Verification attempt rate limit exceeded
post/subscriptions/unsubscribeIdempotently stop a subscription using its private per-message capability
Operation ID
unsubscribeWithCapability
Authentication
Public or capability URL

Request schema

{
  "type": "object",
  "required": [
    "token"
  ],
  "additionalProperties": false,
  "properties": {
    "token": {
      "type": "string",
      "minLength": 43,
      "maxLength": 43
    }
  }
}

Responses

  • 200Subscriber suppressed and all topic rules disabled
  • 400Token invalid
  • 429Unsubscribe attempt rate limit exceeded
get/notificationsList tenant notification delivery status without revealing destinations
Operation ID
listNotificationDeliveries
Authentication
Bearer credential: subscription:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated masked delivery metadata
  • 401Missing or invalid credential
  • 403Credential lacks `subscription:read`
get/matches/{matchId}/outputsList the tenant match's managed output channels and public URLs
Operation ID
listMatchOutputs
Authentication
Bearer credential: output:read

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

Responses

  • 200All managed output channels for the match
  • 401Missing or invalid credential
  • 403Credential lacks `output:read`
  • 404Resource unavailable
patch/matches/{matchId}/outputs/{outputId}Activate or deactivate a tenant match output
Operation ID
updateMatchOutput
Authentication
Bearer credential: output:write

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

  • outputIdpath · required

Request schema

{
  "$ref": "#/components/schemas/UpdateOutput"
}

Responses

  • 200Updated output metadata and public URL
  • 404Resource unavailable
  • 422Invalid request
  • 429Output mutation rate limit exceeded
post/matches/{matchId}/outputs/{outputId}/rotate-keyPermanently replace a public output key and URL
Operation ID
rotateMatchOutputKey
Authentication
Bearer credential: output:write

Parameters

  • matchIdpath · required

    Stable LiveStreamBlog match identifier

  • outputIdpath · required
  • Idempotency-Keyheader · required

    Stable command ID; exact retries return the same replacement key

Responses

  • 200New public key and URL; the prior key is immediately invalid
  • 404Resource unavailable
  • 429Output rotation rate limit exceeded
get/api-keysList tenant API-key metadata without token hashes or full tokens
Operation ID
listApiKeys
Authentication
Bearer credential: api_key:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated API-key metadata
  • 401Missing or invalid credential
  • 403Credential lacks `api_key:read`
post/api-keysCreate a scoped tenant credential and reveal its token once
Operation ID
createApiKey
Authentication
Bearer credential: api_key:write

Request schema

{
  "$ref": "#/components/schemas/CreateApiKey"
}

Responses

  • 201Credential created; `token` is returned only in this response
  • 422Invalid request
  • 429Credential creation rate limit exceeded
delete/api-keys/{keyId}Revoke an API key without deleting its metadata or audit history
Operation ID
revokeApiKey
Authentication
Bearer credential: api_key:write

Parameters

  • keyIdpath · required

Responses

  • 200Revocation timestamp; repeated revocation is idempotent
  • 404Resource unavailable
get/webhooksList tenant webhook endpoints without secret material
Operation ID
listWebhookEndpoints
Authentication
Bearer credential: webhook:read

Responses

  • 200Tenant webhook endpoints
  • 401Missing or invalid credential
  • 403Credential lacks `webhook:read`
post/webhooksCreate a tenant webhook endpoint and reveal its signing secret once
Operation ID
createWebhookEndpoint
Authentication
Bearer credential: webhook:write

Request schema

{
  "$ref": "#/components/schemas/CreateWebhook"
}

Responses

  • 201Endpoint created; `secret` is returned only in this response
  • 422Invalid or non-public webhook URL or invalid subscription
patch/webhooks/{webhookId}Update endpoint name, URL, event subscriptions, or active state
Operation ID
updateWebhookEndpoint
Authentication
Bearer credential: webhook:write

Parameters

  • webhookIdpath · required

Request schema

{
  "$ref": "#/components/schemas/UpdateWebhook"
}

Responses

  • 200Updated endpoint without secret material
  • 404Resource unavailable
  • 422Invalid request
delete/webhooks/{webhookId}Deactivate an endpoint without deleting its delivery history
Operation ID
deactivateWebhookEndpoint
Authentication
Bearer credential: webhook:write

Parameters

  • webhookIdpath · required

Responses

  • 204Endpoint deactivated
  • 404Resource unavailable
post/webhooks/{webhookId}/rotate-secretReplace and reveal a webhook signing secret once
Operation ID
rotateWebhookSecret
Authentication
Bearer credential: webhook:write

Parameters

  • webhookIdpath · required

Responses

  • 200Secret rotated; `secret` is returned only in this response
  • 404Resource unavailable
get/webhooks/{webhookId}/deliveriesList tenant-scoped delivery attempts and terminal states
Operation ID
listWebhookDeliveries
Authentication
Bearer credential: webhook:read

Parameters

  • webhookIdpath · required
  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated delivery log
  • 404Resource unavailable
post/webhooks/{webhookId}/deliveries/{deliveryId}/replayRequeue one dead-lettered delivery with a durable idempotent command
Operation ID
replayDeadWebhookDelivery
Authentication
Bearer credential: webhook:write

Parameters

  • webhookIdpath · required
  • deliveryIdpath · required
  • Idempotency-Keyheader · required

Responses

  • 200Identical replay command safely replayed
  • 202Dead letter reset to pending for immediate worker delivery
  • 404Endpoint or delivery unavailable in this tenant
  • 409Idempotency key reused for another command
  • 422Delivery is not dead or endpoint is inactive
  • 429Manual replay rate limit exceeded
get/mediaList the credential tenant's non-deleted media assets
Operation ID
listMediaAssets
Authentication
Bearer credential: media:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery

Responses

  • 200Cursor-paginated media metadata and stable public URLs
  • 401Missing or invalid API credential
  • 403Credential lacks `media:read`
post/mediaValidate and upload an idempotent tenant image
Operation ID
uploadMediaAsset
Authentication
Bearer credential: media:write

Parameters

  • Idempotency-Keyheader · required

Responses

  • 200Exact idempotent replay
  • 201Image stored
  • 409Idempotency key was reused for different content or metadata
  • 413Upload exceeds 10 MiB
  • 422Missing accessibility text or unsupported content signature
get/media/{mediaId}Retrieve tenant-scoped media metadata
Operation ID
getMediaAsset
Authentication
Bearer credential: media:read

Parameters

  • mediaIdpath · required

    Tenant-scoped media identifier

Responses

  • 200Media metadata and immutable public URL
  • 404Resource unavailable
get/gaablogs/matchesSynchronize tenant matches and current score projections into GAABlogs
Operation ID
listGaaBlogsMatches
Authentication
Bearer credential: gaablogs:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • updated_afterquery

    Return records updated strictly after this timestamp; cursors are preferred while paging a snapshot

Responses

  • 200Tenant-scoped canonical matches
  • 304Representation unchanged for the supplied If-None-Match value
  • 401Missing or invalid API credential
  • 403Credential lacks `gaablogs:read`
get/gaablogs/storiesSynchronize published match and standalone live-blog stories into GAABlogs
Operation ID
listGaaBlogsStories
Authentication
Bearer credential: gaablogs:read

Parameters

  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • updated_afterquery

    Return records updated strictly after this timestamp; cursors are preferred while paging a snapshot

Responses

  • 200Tenant-scoped published stories with canonical targets and source attribution
  • 304Representation unchanged for the supplied If-None-Match value
  • 401Missing or invalid API credential
  • 403Credential lacks `gaablogs:read`
get/gaablogs/mappingsSynchronize stable external identifiers for teams, competitions, and venues
Operation ID
listGaaBlogsMappings
Authentication
Bearer credential: gaablogs:read

Parameters

  • kindquery · required
  • cursorquery

    Opaque cursor returned in `next_cursor`

  • limitquery
  • updated_afterquery

    Return records updated strictly after this timestamp; cursors are preferred while paging a snapshot

Responses

  • 200Tenant-scoped external-to-canonical identifier mappings
  • 304Representation unchanged for the supplied If-None-Match value
  • 400Invalid mapping kind or incremental synchronization parameter
  • 401Missing or invalid API credential
  • 403Credential lacks `gaablogs:read`