sendraven-ai Topics API

The Topics API from sendraven-ai — 4 operation(s) for topics.

Operations 6

GET /v1/topics List topics #
POST /v1/topics Create or update a topic #
DELETE /v1/topics/{key} Delete a topic #
GET /v1/topics/preferences Get one person's topic preferences #
POST /v1/topics/preferences Set one person's topic preferences #
POST /v1/topics/{key}/import Import topic preferences in bulk #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/sendraven-ai:sendraven-ai-topics-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

sendraven-ai-topics-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Sendraven Ai Topics API
  version: 1.0.0
  description: 'Operations tagged Topics across 2 of this provider''s published API definitions: sendraven-ai-api-openapi.json, sendraven-ai-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.sendraven.ai
security:
- bearerAuth: []
tags:
- name: Topics
paths:
  /v1/topics:
    get:
      summary: List topics
      description: Every topic, sorted by name. A topic is a kind of marketing mail someone can opt out of on its own; sending under one makes the message's unsubscribe link opt out of that topic only. Not paged (cap 500).
      x-required-scope: contacts:read
      responses:
        '200':
          description: Topics.
          content:
            application/json:
              schema:
                type: object
                required:
                - object
                - data
                - has_more
                - next_cursor
                properties:
                  object:
                    type: string
                    enum:
                    - list
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Topic'
                  has_more:
                    type: boolean
                    description: 'Not paged: true only when the list hit its cap, meaning there is more than this endpoint can return.'
                  next_cursor:
                    type:
                    - string
                    - 'null'
                    description: Always null; this list is not paged.
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:read scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      tags:
      - Topics
      operationId: getV1Topics
      x-operation-id-source: derived
    post:
      summary: Create or update a topic
      description: 'Creates the topic, or updates the one with this key (201 new, 200 updated), in one write. On an update name is replaced, and description and default_subscribed change only when sent; description: null clears it. The defaults (default_subscribed true, no description) apply only on creation. Default-on suits a newsletter people already expect; default-off suits anything a person should ask for. Changing default_subscribed on an existing topic moves everyone who never chose, so send it on an update only when that is what you mean.'
      x-required-scope: contacts:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - key
              - name
              properties:
                key:
                  type: string
                  pattern: ^[a-z0-9-]+$
                  description: Lower-case letters, digits and hyphens.
                name:
                  type: string
                  minLength: 1
                  maxLength: 120
                description:
                  type:
                  - string
                  - 'null'
                  maxLength: 300
                  description: null clears it on an existing topic.
                default_subscribed:
                  type: boolean
                  description: Whether someone with no recorded preference receives this topic. true on creation when left out; unchanged on update.
      responses:
        '200':
          description: 'Updated: the stored topic.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Topic'
        '201':
          description: Created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Topic'
        '400':
          description: 'invalid_json: the request body is not valid JSON.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:write scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'invalid_request: the body failed validation. details lists each field. Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      parameters:
      - name: Idempotency-Key
        in: header
        schema:
          type: string
        description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
      tags:
      - Topics
      operationId: postV1Topics
      x-operation-id-source: derived
    servers:
    - url: https://api.sendraven.ai
  /v1/topics/{key}:
    delete:
      summary: Delete a topic
      description: 'Deletes the topic and every preference recorded against it. Destructive beyond its name: every opt-out from the topic is erased and cannot be restored, and recreating the key brings back the default for the people who had opted out. Refused with 409 while the topic is used by an active or paused automation, or by a campaign that is draft, scheduled, sending, paused or testing (the message lists them); change or delete those first. Once deleted, a send naming the key is 422 unknown_topic. Do not delete a topic to rename it; POST it again with a new name.'
      x-required-scope: contacts:write
      parameters:
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: The topic's key. Topics are addressed by key, never by id.
      responses:
        '200':
          description: Deleted.
          content:
            application/json:
              schema:
                type: object
                required:
                - key
                - deleted
                properties:
                  key:
                    type: string
                  deleted:
                    type: boolean
                    enum:
                    - true
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:write scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: 'not_found: no topic with this key in the workspace, or it was deleted by another request meanwhile.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'invalid_state: an active or paused automation, or a draft, scheduled, sending, paused or testing campaign, still uses the topic; the message names each one. Nothing was deleted. Retrying will not help until they are changed, deleted or finished.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      tags:
      - Topics
      operationId: deleteV1TopicsByKey
      x-operation-id-source: derived
    servers:
    - url: https://api.sendraven.ai
  /v1/topics/preferences:
    get:
      summary: Get one person's topic preferences
      description: 'Every topic in the workspace, sorted by name, with subscribed resolved for one address: their recorded choice, or the topic''s default. Check this before concluding that mail is failing to arrive; an opt-out looks like a delivery problem from outside. Topic preferences only: an address suppressed for marketing receives no marketing mail whatever this shows, so check GET /v1/suppressions?email= too.'
      x-required-scope: contacts:read
      parameters:
      - name: email
        in: query
        required: true
        schema:
          type: string
        description: The address. Matched case-insensitively. Not validated as an address.
      responses:
        '200':
          description: 'Preferences, one per topic, in the list envelope: not paged, so next_cursor is always null and has_more is true only when the workspace has 500 topics or more.'
          content:
            application/json:
              schema:
                type: object
                required:
                - object
                - data
                - has_more
                - next_cursor
                properties:
                  object:
                    type: string
                    enum:
                    - list
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TopicPreference'
                  has_more:
                    type: boolean
                    description: 'Not paged: true only when the list hit its cap, meaning there is more than this endpoint can return.'
                  next_cursor:
                    type:
                    - string
                    - 'null'
                    description: Always null; this list is not paged.
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:read scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'invalid_request: email is missing or empty.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      tags:
      - Topics
      operationId: getV1TopicsPreferences
      x-operation-id-source: derived
    post:
      summary: Set one person's topic preferences
      description: 'Records a person''s choice for one or more topics. Only do this when the person asked: re-subscribing someone who opted out is what produces spam complaints. Opting out (false) immediately ends their active enrolments in every automation sent under that topic. Opting in (true) restarts nothing and does not lift a suppression. Every key is checked before anything is written, so an unknown_topic refusal saved nothing and the corrected call can be retried whole. Topics not named are left as they are.'
      x-required-scope: contacts:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - email
              - topics
              properties:
                email:
                  type: string
                  format: email
                  description: Stored lower-cased.
                topics:
                  type: object
                  additionalProperties:
                    type: boolean
                  description: 'Topic key to true (subscribed) or false (opted out), e.g. { "newsletter": false }.'
      responses:
        '200':
          description: The person's preferences across every topic after the change, in the same list envelope as GET.
          content:
            application/json:
              schema:
                type: object
                required:
                - object
                - data
                - has_more
                - next_cursor
                properties:
                  object:
                    type: string
                    enum:
                    - list
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TopicPreference'
                  has_more:
                    type: boolean
                    description: 'Not paged: true only when the list hit its cap, meaning there is more than this endpoint can return.'
                  next_cursor:
                    type:
                    - string
                    - 'null'
                    description: Always null; this list is not paged.
        '400':
          description: 'invalid_json: the request body is not valid JSON.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:write scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'invalid_request: email is not an address, or topics is missing or has a non-boolean value (no details). unknown_topic: a key names no topic in this workspace (message starts with the field, e.g. "topics.promos:"); nothing was saved. Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      parameters:
      - name: Idempotency-Key
        in: header
        schema:
          type: string
        description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
      tags:
      - Topics
      operationId: postV1TopicsPreferences
      x-operation-id-source: derived
    servers:
    - url: https://api.sendraven.ai
  /v1/topics/{key}/import:
    post:
      summary: Import topic preferences in bulk
      description: 'Sets the same preference for up to 50,000 addresses on one topic, overwriting what they had: the migration path for who opted out of which list at a previous provider, to run before the first send under the topic. subscribed: false immediately ends those addresses'' active enrolments in automations sent under this topic; true restarts nothing. Does not touch suppressions; import those with POST /v1/suppressions/batch. The body is limited to 5 MB, so split very long lists.'
      x-required-scope: contacts:write
      parameters:
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: The topic's key. Topics are addressed by key, never by id.
      - name: Idempotency-Key
        in: header
        schema:
          type: string
        description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - emails
              - subscribed
              properties:
                emails:
                  type: array
                  minItems: 1
                  maxItems: 50000
                  items:
                    type: string
                    format: email
                  description: Lower-cased; duplicates written once.
                subscribed:
                  type: boolean
                  description: false records an opt-out for every address, true a subscription.
      responses:
        '201':
          description: Imported.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicImportResult'
        '400':
          description: 'invalid_json: the request body is not valid JSON.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'forbidden: the key lacks the contacts:write scope. The message names it.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: 'not_found: no topic with this key in the workspace. Checked before the body.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'invalid_request: emails missing, empty, over 50,000 or containing a non-address, or subscribed missing (no details). Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      tags:
      - Topics
      operationId: postV1TopicsByKeyImport
      x-operation-id-source: derived
    servers:
    - url: https://api.sendraven.ai
components:
  schemas:
    TopicImportResult:
      type: object
      required:
      - topic
      - written
      properties:
        topic:
          type: string
          description: The topic key.
        written:
          type: integer
          description: Distinct addresses whose preference was recorded.
    Topic:
      type: object
      required:
      - id
      - key
      - name
      - description
      - default_subscribed
      - created_at
      properties:
        id:
          type: string
          format: uuid
          description: Not used by any endpoint; topics are addressed by key.
        key:
          type: string
          pattern: ^[a-z0-9-]+$
          description: Unique within the workspace. The identifier used in paths, in topic on POST /v1/emails, in topic_key on campaigns and automations, and in unsubscribe links.
        name:
          type: string
          description: Shown to the person on the preference page.
        description:
          type:
          - string
          - 'null'
          description: Shown under the name. null when not set.
        default_subscribed:
          type: boolean
          description: Whether someone with no recorded preference receives this topic. Defaults are never written out as rows, so changing this moves everyone who never chose.
        created_at:
          type: string
          format: date-time
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - type
          - message
          properties:
            type:
              type: string
              description: 'Stable and safe to branch on, and the same status on every route: invalid_request (422), invalid_json (400), payload_too_large (413), unauthorized (401), forbidden (403), not_found (404), conflict (409, an identifier already taken), invalid_state (409, the resource''s current state does not allow this), plan_limit_reached (402), payment_method_required (402), billing_past_due (402), budget_exceeded (402), no_verified_identity (422), missing_variables (422), unknown_topic (422), idempotency_in_progress (409), idempotency_key_reused (422), approval_in_progress (409), rate_limited (429), daily_limit (429), recipient_not_allowed (403), invalid_schedule (422), warmup_limit (422), no_postal_address (422), workspace_suspended (422), gone (410), ses_error (502), internal_error (500), service_unavailable (503).'
            message:
              type: string
              description: For people; may change.
            details:
              type: array
              items:
                type: object
                additionalProperties: true
              description: 'On many 422 invalid_request answers: one entry per field that failed validation.'
            missing:
              type: array
              items:
                type: string
              description: 'Only on missing_variables, and always there: the names of the template variables that were not supplied.'
    TopicPreference:
      type: object
      description: A topic with subscribed resolved for one address.
      required:
      - id
      - key
      - name
      - description
      - default_subscribed
      - created_at
      - subscribed
      properties:
        id:
          type: string
          format: uuid
        key:
          type: string
        name:
          type: string
        description:
          type:
          - string
          - 'null'
        default_subscribed:
          type: boolean
        created_at:
          type: string
          format: date-time
        subscribed:
          type: boolean
          description: The person's recorded choice where there is one, otherwise the topic's default_subscribed.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An API key of the form sk_live_…, created at /developers, or an OAuth access token (srv_oat_…). An OAuth token carries its grant's scopes but none of an API key's guardrails, and cannot decide approvals.
x-refined-from:
- sendraven-ai-api-openapi.json
- sendraven-ai-openapi.json