openapi: 3.1.0 info: title: Captivate API version: '1.0' description: >- Public REST API for the Captivate podcast hosting, distribution, and analytics platform. Authenticate a user with their user ID and API token to obtain a Bearer token, then manage shows, episodes, and media and read detailed listening analytics (insights). Endpoints, paths, methods, and request fields in this document are transcribed from Captivate's public Postman documentation at https://docs.captivate.fm. Response schemas are modeled honestly - Captivate's public docs describe the requests and fields but do not publish full JSON response schemas, so response bodies below are generic objects and marked as modeled. contact: name: Captivate API Support email: api@captivate.fm url: https://docs.captivate.fm/ x-endpoints-source: >- Paths and request fields confirmed from the public Captivate API Postman collection (docs.captivate.fm). Response bodies are modeled. servers: - url: https://api.captivate.fm description: Captivate production API tags: - name: Authentication description: Exchange a user ID and API token for a Bearer token. - name: Users description: Read a user and list the shows they can access or manage. - name: Shows description: Read and update shows, upload artwork, get the RSS feed URL. - name: Episodes description: List, read, create, and update episodes. - name: Media description: Upload, read, list, and search a show's audio media. - name: Analytics description: Podcast and episode listening analytics (insights). paths: /authenticate/token: post: operationId: authenticateUser tags: - Authentication summary: Authenticate User description: >- All requests must be authenticated using a Bearer token for the user. Obtain the token by sending the user's ID and their API token (both found in the API section of the Captivate account). Returns a Bearer token used in the Authorization header for all other requests. security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: - username - token properties: username: type: string description: The Captivate user ID (UUID). example: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx token: type: string description: The user's API token from their Captivate account. responses: '200': description: Authentication succeeded; a Bearer token is returned (modeled). content: application/json: schema: $ref: '#/components/schemas/AuthToken' '401': $ref: '#/components/responses/Unauthorized' /users/{id}: get: operationId: getUser tags: - Users summary: Get User description: Get a user record by user ID. parameters: - $ref: '#/components/parameters/UserId' responses: '200': description: The user record (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /users/{id}/shows: get: operationId: getUserShows tags: - Users summary: Get Users Shows description: The shows that this user can access regardless of their role. parameters: - $ref: '#/components/parameters/UserId' responses: '200': description: A list of shows the user can access (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /users/{id}/shows/manager: get: operationId: getUserManagedShows tags: - Users summary: Get Users Managed Shows description: >- The shows that the user is manager or owner of; they can create and invite new users to these shows. parameters: - $ref: '#/components/parameters/UserId' responses: '200': description: A list of shows the user manages or owns (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/: get: operationId: getShow tags: - Shows summary: Get Show description: Get the show information by the show ID. parameters: - $ref: '#/components/parameters/ShowId' responses: '200': description: The show record (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}: put: operationId: updateShow tags: - Shows summary: Update Show description: Update the show's metadata. parameters: - $ref: '#/components/parameters/ShowId' requestBody: required: true content: multipart/form-data: schema: type: object properties: title: type: string example: My Demo Show description: type: string summary: type: string subtitle: type: string author: type: string name: type: string 'categories[0]': type: string description: Apple Podcasts category code, e.g. 01.00. itunes_email: type: string copyright: type: string explicit: type: string description: e.g. clean, explicit. order: type: string example: DESC limit: type: string type: type: string description: e.g. episodic or serial. language: type: string example: en donation_link: type: string link: type: string third_party_analytics: type: string description: Third-party analytics prefix, e.g. a Chartable tracking URL. responses: '200': description: The updated show (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/artwork: post: operationId: createShowArtwork tags: - Shows summary: Create Show Artwork description: >- Upload the show's artwork. The file must be a JPG or PNG in the RGB colorspace (not CMYK), completely square, with a minimum of 1400px height. parameters: - $ref: '#/components/parameters/ShowId' requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary description: Square JPG or PNG artwork, RGB, minimum 1400px. responses: '200': description: Artwork accepted (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/feed: get: operationId: getShowFeedUrl tags: - Shows summary: Get Show Feed URL description: Get the public RSS feed URL for this show. parameters: - $ref: '#/components/parameters/ShowId' responses: '200': description: The RSS feed URL (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/episodes: get: operationId: getShowEpisodes tags: - Episodes summary: Get Show Episodes description: >- A full breakdown of all the episodes for this show plus a count of the total number of episodes. parameters: - $ref: '#/components/parameters/ShowId' responses: '200': description: The show's episodes and a count (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/episodes/scheduled: get: operationId: getShowScheduledEpisodes tags: - Episodes summary: Get Show Scheduled Episodes description: All scheduled (future) episodes for this show plus a count. parameters: - $ref: '#/components/parameters/ShowId' responses: '200': description: The show's scheduled episodes and a count (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /episodes/{id}: get: operationId: getEpisode tags: - Episodes summary: Get Episode description: Get the full information for an episode by episode ID. parameters: - $ref: '#/components/parameters/EpisodeId' responses: '200': description: The episode record (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' put: operationId: updateEpisode tags: - Episodes summary: Update Episode description: Update an existing episode. parameters: - $ref: '#/components/parameters/EpisodeId' requestBody: required: true content: multipart/form-data: schema: $ref: '#/components/schemas/EpisodeInput' responses: '200': description: The updated episode (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /episodes: post: operationId: createEpisode tags: - Episodes summary: Create Episode description: Create an episode with the following parameters. requestBody: required: true content: multipart/form-data: schema: $ref: '#/components/schemas/EpisodeInput' responses: '200': description: The created episode (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /media/{id}: get: operationId: getMedia tags: - Media summary: Get Media description: Get the information for this media ID. parameters: - $ref: '#/components/parameters/MediaId' responses: '200': description: The media record (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/media: post: operationId: uploadMedia tags: - Media summary: Upload Media description: >- Upload a media (audio) file and assign it to the given show ID. Captivate processes the file server-side. parameters: - $ref: '#/components/parameters/ShowId' requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary description: The audio media file to upload. responses: '200': description: The uploaded media record (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' get: operationId: getShowMedia tags: - Media summary: Get Show Media description: >- Get all media for the given show ID. Media cannot be shared across shows, so this is scoped to a single show. parameters: - $ref: '#/components/parameters/ShowId' - name: offset in: query schema: type: integer default: 0 - name: order in: query schema: type: string default: created_at - name: sort in: query schema: type: string enum: - ASC - DESC default: DESC responses: '200': description: The show's media list (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /shows/{id}/media/search: get: operationId: searchShowMedia tags: - Media summary: Search Show Media description: Search a show's media by media name. parameters: - $ref: '#/components/parameters/ShowId' - name: search in: query required: true schema: type: string description: The media name search query. - name: offset in: query schema: type: integer default: 0 - name: order in: query schema: type: string default: created_at - name: sort in: query schema: type: string enum: - ASC - DESC default: DESC responses: '200': description: Matching media (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/overview: get: operationId: getPodcastOverviewAnalytics tags: - Analytics summary: Get Overview Analytics for Podcast description: Overview analytics for a podcast over a date range. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/StartQuery' - $ref: '#/components/parameters/EndQuery' - name: includeTopEpisodes in: query schema: type: boolean default: true responses: '200': description: Podcast overview analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/overview/{episodeId}: get: operationId: getEpisodeOverviewAnalytics tags: - Analytics summary: Get Overview Analytics for a specific Episode description: Overview analytics for a specific episode over a date range. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/InsightsEpisodeId' - $ref: '#/components/parameters/StartQuery' - $ref: '#/components/parameters/EndQuery' responses: '200': description: Episode overview analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/averages: get: operationId: getPodcastAverageAnalytics tags: - Analytics summary: Get Average Analytics for Podcast description: Average analytics for a podcast over an interval window. parameters: - $ref: '#/components/parameters/InsightsShowId' - name: intervalDays in: query schema: type: integer default: 28 responses: '200': description: Podcast average analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/total: get: operationId: getPodcastAllTimeTotal tags: - Analytics summary: Get All-Time Total for Podcast description: All-time total analytics for a podcast. parameters: - $ref: '#/components/parameters/InsightsShowId' responses: '200': description: Podcast all-time total (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/total/{episodeId}: get: operationId: getEpisodeAllTimeTotal tags: - Analytics summary: Get All-Time Total for Episode description: All-time total analytics for a specific episode. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/InsightsEpisodeId' responses: '200': description: Episode all-time total (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/monthly: get: operationId: getPodcastMonthlyAnalytics tags: - Analytics summary: Get Month-by-Month Analytics for Podcast description: Month-by-month analytics series for a podcast. parameters: - $ref: '#/components/parameters/InsightsShowId' responses: '200': description: Podcast monthly analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/monthly/{episodeId}: get: operationId: getEpisodeMonthlyAnalytics tags: - Analytics summary: Get Month-by-Month Analytics for Episode description: Month-by-month analytics series for a specific episode. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/InsightsEpisodeId' responses: '200': description: Episode monthly analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/range: post: operationId: getPodcastRangeAnalytics tags: - Analytics summary: Get Analytics in Range for Podcast description: >- Analytics for a podcast over an arbitrary date range, broken down by the requested dimension types. parameters: - $ref: '#/components/parameters/InsightsShowId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RangeRequest' responses: '200': description: Podcast range analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/range/{episodeId}: post: operationId: getEpisodeRangeAnalytics tags: - Analytics summary: Get Analytics in Range for Episode description: >- Analytics for a specific episode over an arbitrary date range, broken down by the requested dimension types. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/InsightsEpisodeId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RangeRequest' responses: '200': description: Episode range analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/compare: post: operationId: compareEpisodeAnalytics tags: - Analytics summary: Get Analytics Comparison between Episodes description: Compare analytics across a set of episodes. parameters: - $ref: '#/components/parameters/InsightsShowId' requestBody: required: true content: application/json: schema: type: array items: type: object properties: id: type: string title: type: string published_date: type: string format: date-time responses: '200': description: Episode comparison analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' /insights/{showId}/web-player/{episodeId}: post: operationId: getWebPlayerAnalytics tags: - Analytics summary: Get Web Player Analytics for Podcast description: Web-player analytics for a podcast, scoped to an episode context. parameters: - $ref: '#/components/parameters/InsightsShowId' - $ref: '#/components/parameters/InsightsEpisodeId' requestBody: required: true content: application/json: schema: type: object properties: dateRange: type: object properties: gte: type: string format: date-time lte: type: string format: date-time duration: type: string timezone: type: string example: America/New_York responses: '200': description: Web-player analytics (modeled). content: application/json: schema: $ref: '#/components/schemas/GenericObject' '401': $ref: '#/components/responses/Unauthorized' components: securitySchemes: bearerAuth: type: http scheme: bearer description: >- Bearer token obtained from POST /authenticate/token. Sent as Authorization: Bearer {token}. parameters: UserId: name: id in: path required: true description: The Captivate user ID (UUID). schema: type: string ShowId: name: id in: path required: true description: The show ID (UUID). schema: type: string EpisodeId: name: id in: path required: true description: The episode ID (UUID). schema: type: string MediaId: name: id in: path required: true description: The media ID (UUID). schema: type: string InsightsShowId: name: showId in: path required: true description: The show ID (UUID) for insights. schema: type: string InsightsEpisodeId: name: episodeId in: path required: true description: The episode ID (UUID) for insights. schema: type: string StartQuery: name: start in: query schema: type: string format: date-time example: '2022-09-01T00:00:00.000Z' EndQuery: name: end in: query schema: type: string format: date-time example: '2022-09-01T00:00:00.000Z' responses: Unauthorized: description: Missing or invalid Bearer token. content: application/json: schema: $ref: '#/components/schemas/GenericObject' schemas: AuthToken: type: object description: >- Modeled authentication response. Captivate returns a Bearer token used for all subsequent requests; the exact envelope is not published. properties: success: type: boolean user: type: object token: type: string EpisodeInput: type: object description: Fields for creating or updating an episode (multipart form-data). required: - shows_id - title properties: shows_id: type: string description: The show ID (UUID) the episode belongs to. title: type: string example: My Demo Episode itunes_title: type: string media_id: type: string description: The uploaded media ID (UUID) to attach as the episode audio. date: type: string description: Publish date, format YYYY-MM-DD HH:mm:ss. status: type: string description: e.g. Draft, Published. example: Draft shownotes: type: string summary: type: string itunes_subtitle: type: string author: type: string episode_art: type: string description: URL to episode artwork. explicit: type: string episode_type: type: string description: e.g. full, trailer, bonus. episode_season: type: string episode_number: type: string donation_link: type: string donation_text: type: string link: type: string itunes_block: type: string description: 'true or false: whether to block the episode from Apple Podcasts.' RangeRequest: type: object description: Request body for range analytics. properties: start: type: string format: date-time end: type: string format: date-time interval: type: string example: 1d timezone: type: string example: America/New_York countryCode: type: - string - 'null' types: type: array items: type: string enum: - byLocation - byUserAgentBrowser - byUserAgentOs - byUserAgentDevice - byEpisode - byPrivateSubscriber GenericObject: type: object description: >- Modeled response object. Captivate's public documentation describes requests and fields but does not publish full JSON response schemas, so response bodies are represented generically. additionalProperties: true security: - bearerAuth: []