# ActivationKing API (v1)

Access to your own ActivationKing data: read events, sessions, results, subscriptions and credits; read and write Ops Calendar companies, event jobs and deals (for example to push jobs won in your CRM).

**Authentication:** send your key as `Authorization: Bearer ak_live_...`. Create and revoke keys at https://activationking.com/dashboard/api-keys. A key only sees the data of the account that created it.

**Limits:** 300 requests per minute per key. Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`; over the limit you get `429` with `Retry-After` (seconds).

**Paging:** list endpoints return `{ items, nextCursor, totalCount }`. Pass `nextCursor` back as `cursor` until it is `null`. Cursors are opaque; `limit` is at most 100.

**Errors:** `{ "error": { "code": "not_found", "message": "..." } }`. A record that belongs to another account is reported as `404`.

**Ops Calendar (`/v1/ops/*`):** send `X-Organization-Id` (ids are listed by `/v1/me`). The key acts with its owner's role in that organization (for example `Jobs.Create`, `Crm.Edit`, `Deal.Edit`) and the organization needs an active Ops Calendar subscription (`402` otherwise). To sync from another system without duplicates use `PUT /v1/ops/companies/external/{source}/{externalId}` and `PUT /v1/ops/jobs/external/{source}/{externalId}`: the first call creates, later calls update the same record. PATCH changes only the fields you send.

**AI agents:** MCP server at `https://api.activationking.com/mcp` (same key); Markdown reference at `https://api.activationking.com/llms.txt` and `/llms-full.txt`.

Base URL: https://api.activationking.com. JSON bodies are camelCase. Times are UTC (ISO 8601). In PATCH bodies an omitted or null field is left unchanged; a list that is sent replaces the whole list.

## MCP server

Connect an AI agent (Claude, ChatGPT, Cursor...) to `https://api.activationking.com/mcp` (Streamable HTTP) with the header `Authorization: Bearer ak_live_...`. Same key, limits and role permissions as the REST API. Write tools are marked as changing data, so clients ask before calling them.

- `get_account`: Your ActivationKing account: totals and the organizations you belong to (organizationId is needed by the ops_* tools).
- `get_credit_balance`: Your AI credit balance.
- `list_events`: Your events (photo booth, games...), newest first. Pass nextCursor back as cursor for the next page.
- `get_event`: One event with its session count and share link.
- `get_event_stats`: Totals for one event: sessions, successful sessions, prints and AI credits spent (from the credit ledger).
- `list_event_sessions`: Sessions (guest visits) of an event in arrival order, with result photo/video links.
- `get_session`: One session with its result media.
- `ops_reference_data`: Values an Ops job needs: phases (for planned times), event and venue types, members (for responsibleUserIds), products and deal statuses.
- `ops_list_companies`: Companies (clients, brands, agencies, suppliers) of an Ops organization.
- `ops_get_company`: One company with contacts and billing details.
- `ops_list_jobs`: Event jobs of an Ops organization, ordered by planned start. Optional from/to (UTC) keep jobs whose planned phases overlap the range.
- `ops_get_job`: One event job.
- `ops_get_deal`: The deal (price lines, status, currency) of a job. Needs the Deal.View permission.
- `ops_save_company` (writes): Create or update a company. With externalSource + externalId (your system's id) the same company is updated on later calls; with companyId the given company is updated; otherwise a new company is created. Only the fields you pass change. Billing fields need Crm.EditBilling.
- `ops_delete_company` (writes): Delete a company. Refused while a job uses it; archive it instead with ops_save_company (isArchived=true).
- `ops_save_job` (writes): Create or update an event job (Jobs.Create / Jobs.Edit). With externalSource + externalId the same job is updated on later calls; with jobId the given job is updated; otherwise a new job is created and a deal is opened for it automatically. Only the fields you pass change. Use ops_reference_data for phase slugs, types, member and product ids.
- `ops_delete_job` (writes): Delete an event job together with its deal, equipment assignments and comments (Jobs.Edit).
- `ops_update_deal` (writes): Change a job's deal: status column, currency, price lines (a lines list replaces all lines), dates, notes. Needs Deal.Edit.

## Endpoints

### GET /v1/me

Your account and totals

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `MeV1`

### GET /v1/subscriptions

Your subscriptions, newest first

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `PageV1OfSubscriptionV1`

### GET /v1/credits

Your AI credit balance

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `CreditsV1`

### GET /v1/events

Your events, newest first

Archive (V1) events come after current ones. Optional appIdentifier filter, e.g. com.activationking.photobooth.

Parameters:
- `cursor` (query): string
- `limit` (query): integer
- `appIdentifier` (query): string

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `PageV1OfEventV1`
- `400`: `ApiErrorV1`

### GET /v1/events/{eventId}

One event

Parameters:
- `eventId` (path, required): string

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `EventV1`
- `404`: `ApiErrorV1`

### GET /v1/events/{eventId}/sessions

Sessions (guest visits) of an event, in arrival order

Stable while the event is live: new sessions do not shift pages. Media lists the result photos/videos.

Parameters:
- `eventId` (path, required): string
- `cursor` (query): string
- `limit` (query): integer

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `PageV1OfSessionV1`
- `400`: `ApiErrorV1`
- `404`: `ApiErrorV1`

### GET /v1/events/{eventId}/stats

Totals for one event

Parameters:
- `eventId` (path, required): string

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `EventStatsV1`
- `404`: `ApiErrorV1`

### GET /v1/events/{eventId}/leads

Lead form and survey answers of an event

Same table as the dashboard Excel export: one row per participant, first column SessionId.

Parameters:
- `eventId` (path, required): string
- `cursor` (query): string
- `limit` (query): integer

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `LeadTableV1`
- `400`: `ApiErrorV1`
- `404`: `ApiErrorV1`

### GET /v1/sessions/{sessionId}

One session

Parameters:
- `sessionId` (path, required): string

Responses:
- `401`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `SessionV1`
- `404`: `ApiErrorV1`

### GET /v1/ops/companies

Companies (clients, brands, agencies, suppliers) of the organization

Requires the `X-Organization-Id` header.

Parameters:
- `cursor` (query): string
- `limit` (query): integer
- `search` (query): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `PageV1OfOpsCompanyV1`

### POST /v1/ops/companies

Create a company (Crm.Edit; billing fields need Crm.EditBilling)

Requires the `X-Organization-Id` header.

Body: `OpsCompanyWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `201`: `OpsCompanyV1`

### GET /v1/ops/companies/{id}

One company

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsCompanyV1`

### PATCH /v1/ops/companies/{id}

Change the given fields of a company; omitted fields stay as they are

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Body: `OpsCompanyWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsCompanyV1`

### DELETE /v1/ops/companies/{id}

Delete a company (refused with 409 in_use while a job uses it)

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `204`

### PUT /v1/ops/companies/external/{source}/{externalId}

Create or update a company by your system's id

The first call creates the company and binds it to (source, externalId); later calls update the same company. Use this from a CRM to avoid duplicates.

Requires the `X-Organization-Id` header.

Parameters:
- `source` (path, required): string
- `externalId` (path, required): string

Body: `OpsCompanyWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsCompanyV1`
- `201`: `OpsCompanyV1`

### GET /v1/ops/jobs

Event jobs of the organization, by planned start

Optional from/to (UTC) keep jobs whose planned phases overlap the range.

Requires the `X-Organization-Id` header.

Parameters:
- `cursor` (query): string
- `limit` (query): integer
- `from` (query): string (date-time)
- `to` (query): string (date-time)

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `PageV1OfOpsJobV1`

### POST /v1/ops/jobs

Create an event job (Jobs.Create). A deal is opened for it automatically.

Requires the `X-Organization-Id` header.

Body: `OpsJobWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `201`: `OpsJobV1`

### GET /v1/ops/jobs/{id}

One event job

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsJobV1`

### PATCH /v1/ops/jobs/{id}

Change the given fields of a job; omitted fields stay as they are

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Body: `OpsJobWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsJobV1`

### DELETE /v1/ops/jobs/{id}

Delete a job (Jobs.Edit); its deal, equipment and comments go with it

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `204`

### PUT /v1/ops/jobs/external/{source}/{externalId}

Create or update a job by your system's id

The first call creates the job and binds it to (source, externalId); later calls update the same job.

Requires the `X-Organization-Id` header.

Parameters:
- `source` (path, required): string
- `externalId` (path, required): string

Body: `OpsJobWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsJobV1`
- `201`: `OpsJobV1`

### GET /v1/ops/jobs/{id}/deal

The deal (price, status) of a job (Deal.View)

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsDealV1`

### PATCH /v1/ops/jobs/{id}/deal

Change the deal of a job (Deal.Edit)

Requires the `X-Organization-Id` header.

Parameters:
- `id` (path, required): string

Body: `OpsDealWriteV1`

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsDealV1`

### GET /v1/ops/phases

Phases a job can plan (setup, event, teardown...)

Requires the `X-Organization-Id` header.

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: array of `OpsPhaseV1`

### GET /v1/ops/event-types

Known event and venue types

Requires the `X-Organization-Id` header.

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: `OpsTypesV1`

### GET /v1/ops/members

Accepted members (user ids for responsibleUserIds)

Requires the `X-Organization-Id` header.

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: array of `OpsMemberV1`

### GET /v1/ops/products

Products a job line can use

Requires the `X-Organization-Id` header.

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: array of `OpsProductV1`

### GET /v1/ops/deal-statuses

Deal columns (statusId values)

Requires the `X-Organization-Id` header.

Responses:
- `400`: `ApiErrorV1`
- `401`: `ApiErrorV1`
- `402`: `ApiErrorV1`
- `403`: `ApiErrorV1`
- `404`: `ApiErrorV1`
- `409`: `ApiErrorV1`
- `429`: `ApiErrorV1`
- `200`: array of `OpsDealStatusV1`

## Models

### AccountStatsV1

- `totalEvents`: integer
- `eventsThisMonth`: integer
- `totalSessions`: integer
- `lastActivityAt`: string (date-time) | null

### ApiErrorBodyV1

- `code`: string
- `message`: string

### ApiErrorV1

- `error`: `ApiErrorBodyV1`

### CreditSpendV1

- `consumed`: number
- `refunded`: number
- `net`: number

### CreditsV1

- `balance`: number

### EventStatsV1

- `eventId`: string
- `sessions`: integer
- `successfulSessions`: integer
- `prints`: integer
- `testPrints`: integer
- `credits`: `CreditSpendV1`
- `lastActivityAt`: string (date-time)
- `isArchive`: boolean

### EventV1

- `id`: string
- `name`: string
- `motto`: string | null
- `appIdentifier`: string | null
- `createdAt`: string (date-time)
- `lastActivityAt`: string (date-time)
- `sessionCount`: integer
- `shareUrl`: string | null
- `coverImageUrl`: string | null
- `isArchive`: boolean

### ExternalRefV1

- `source`: string
- `id`: string

### LeadTableV1

- `columns`: array of string
- `rows`: array of array of any
- `nextCursor`: string | null
- `totalCount`: integer

### MediaV1

- `url`: string
- `type`: string
- `aspectRatio`: number

### MeV1

- `id`: string
- `email`: string | null
- `stats`: `AccountStatsV1`
- `organizations`: array of `OrganizationV1`

### OpsCompanyBillingV1

- `legalName`: string | null
- `taxNumber`: string | null
- `taxOffice`: string | null
- `address`: string | null
- `district`: string | null
- `city`: string | null
- `postalCode`: string | null
- `country`: string | null
- `email`: string | null
- `paymentTermDays`: integer | null
- `isIndividual`: boolean

### OpsCompanyBillingWriteV1

- `legalName`: string | null (optional)
- `taxNumber`: string | null (optional)
- `taxOffice`: string | null (optional)
- `address`: string | null (optional)
- `district`: string | null (optional)
- `city`: string | null (optional)
- `postalCode`: string | null (optional)
- `country`: string | null (optional)
- `email`: string | null (optional)
- `paymentTermDays`: integer | null (optional)
- `isIndividual`: boolean | null (optional)

### OpsCompanyV1

- `id`: string
- `external`: `ExternalRefV1` | null
- `name`: string | null
- `type`: string
- `website`: string | null
- `phone`: string | null
- `notes`: string | null
- `billing`: `OpsCompanyBillingV1`
- `contacts`: array of `OpsContactV1`
- `isArchived`: boolean
- `version`: integer
- `updatedAt`: string (date-time)

### OpsCompanyWriteV1

- `name`: string | null (optional)
- `type`: string | null (optional)
- `website`: string | null (optional)
- `phone`: string | null (optional)
- `notes`: string | null (optional)
- `billing`: `OpsCompanyBillingWriteV1` | null (optional)
- `contacts`: array of `OpsContactV1` | null (optional)
- `isArchived`: boolean | null (optional)

### OpsContactV1

- `id`: string | null
- `name`: string | null
- `title`: string | null
- `phone`: string | null
- `email`: string | null
- `isPrimary`: boolean
- `note`: string | null

### OpsDealLineV1

- `lineId`: string | null
- `description`: string | null
- `amountExclVat`: number
- `vatRatePercent`: number

### OpsDealStatusV1

- `id`: string
- `name`: string | null
- `sortOrder`: integer

### OpsDealV1

- `id`: string
- `jobId`: string
- `statusId`: string | null
- `currency`: string | null
- `vatExempt`: boolean
- `quotedAt`: string (date-time) | null
- `paymentDue`: string (date-time) | null
- `notes`: string | null
- `lines`: array of `OpsDealLineV1`
- `totalExclVat`: number
- `version`: integer
- `updatedAt`: string (date-time)

### OpsDealWriteV1

- `statusId`: string | null (optional)
- `currency`: string | null (optional)
- `vatExempt`: boolean | null (optional)
- `quotedAt`: string (date-time) | null (optional)
- `paymentDue`: string (date-time) | null (optional)
- `notes`: string | null (optional)
- `lines`: array of `OpsDealLineV1` | null (optional)

### OpsJobContactV1

- `id`: string | null
- `companyId`: string | null
- `contactId`: string | null
- `name`: string | null
- `phone`: string | null
- `note`: string | null

### OpsJobPhaseV1

- `phase`: string
- `plannedStart`: string (date-time)
- `plannedEnd`: string (date-time) | null
- `actualStart`: string (date-time) | null
- `actualEnd`: string (date-time) | null

### OpsJobPhaseWriteV1

- `phase`: string
- `plannedStart`: string (date-time)
- `plannedEnd`: string (date-time) | null

### OpsJobProductV1

- `lineId`: string | null
- `productId`: string
- `quantity`: integer

### OpsJobProductWriteV1

- `productId`: string
- `quantity`: integer

### OpsJobV1

- `id`: string
- `external`: `ExternalRefV1` | null
- `name`: string | null
- `clientCompanyId`: string | null
- `brandCompanyId`: string | null
- `venue`: `OpsJobVenueV1`
- `eventType`: string | null
- `notes`: string | null
- `status`: string
- `phases`: array of `OpsJobPhaseV1`
- `products`: array of `OpsJobProductV1`
- `onSiteContacts`: array of `OpsJobContactV1`
- `responsibleUserIds`: array of string
- `releasedToOperations`: boolean
- `equipmentReserved`: boolean
- `version`: integer
- `updatedAt`: string (date-time)

### OpsJobVenueV1

- `name`: string | null
- `type`: string | null
- `address`: string | null
- `latitude`: number | null
- `longitude`: number | null
- `timeZone`: string | null

### OpsJobVenueWriteV1

- `name`: string | null (optional)
- `type`: string | null (optional)
- `address`: string | null (optional)
- `latitude`: number | null (optional)
- `longitude`: number | null (optional)
- `timeZone`: string | null (optional)

### OpsJobWriteV1

- `name`: string | null (optional)
- `clientCompanyId`: string | null (optional)
- `brandCompanyId`: string | null (optional)
- `venue`: `OpsJobVenueWriteV1` | null (optional)
- `eventType`: string | null (optional)
- `notes`: string | null (optional)
- `phases`: array of `OpsJobPhaseWriteV1` | null (optional)
- `products`: array of `OpsJobProductWriteV1` | null (optional)
- `onSiteContacts`: array of `OpsJobContactV1` | null (optional)
- `responsibleUserIds`: array of string | null (optional)
- `status`: string | null (optional)
- `statusNote`: string | null (optional)
- `startApproved`: boolean | null (optional)

### OpsMemberV1

- `userId`: string
- `email`: string | null
- `displayName`: string | null
- `role`: string

### OpsPhaseV1

- `slug`: string
- `name`: string | null
- `sortOrder`: integer

### OpsProductV1

- `id`: string
- `name`: string | null
- `description`: string | null
- `isArchived`: boolean

### OpsTypesV1

- `eventTypes`: array of string
- `venueTypes`: array of string

### OrganizationV1

- `id`: string
- `name`: string | null
- `isOwner`: boolean
- `suspended`: boolean

### PageV1OfEventV1

- `items`: array of `EventV1`
- `nextCursor`: string | null
- `totalCount`: integer

### PageV1OfOpsCompanyV1

- `items`: array of `OpsCompanyV1`
- `nextCursor`: string | null
- `totalCount`: integer

### PageV1OfOpsJobV1

- `items`: array of `OpsJobV1`
- `nextCursor`: string | null
- `totalCount`: integer

### PageV1OfSessionV1

- `items`: array of `SessionV1`
- `nextCursor`: string | null
- `totalCount`: integer

### PageV1OfSubscriptionV1

- `items`: array of `SubscriptionV1`
- `nextCursor`: string | null
- `totalCount`: integer

### SessionV1

- `id`: string
- `eventId`: string
- `capturedAt`: string (date-time)
- `lastActivityAt`: string (date-time)
- `status`: string
- `result`: string | null
- `leadCaptured`: boolean
- `coverImageUrl`: string | null
- `shareUrl`: string | null
- `media`: array of `MediaV1`

### SubscriptionV1

- `id`: string
- `product`: string | null
- `plan`: string | null
- `status`: string
- `isTrial`: boolean
- `isPerpetual`: boolean
- `accessExpiresAt`: string (date-time) | null
- `nextPaymentAt`: string (date-time) | null
- `seats`: integer
- `store`: string | null
- `isSandbox`: boolean
- `createdAt`: string (date-time)

