Cavuno Media API

Upload and manage logos and other binary assets.

Operations 4

POST /media/upload Upload a media file #
GET /media/{id} Retrieve a media file #
POST /media/upload-intents Create a staged media upload intent #
POST /media/upload-intents/{intentId}/complete Complete a staged media upload #

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/cavuno-com:cavuno-com-media-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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

cavuno-com-media-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Cavuno v1 REST Media API
  version: 1.0.0
  description: 'The Cavuno API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs. ## Base URL


    Production: `https://api.cavuno.com/v1`


    All API requests must be made over HTTPS. Calls made over plain HTTP will fail. ## Authentication


    The Cavuno API uses API keys to authenticate requests. You can view and manage your API keys in the Cavuno dashboard, under Settings → Developer → API keys. Cavuno API keys have the prefix `cavuno_live_`. Your API keys carry many privileges, so be sure to keep them secure. Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth. Authentication to the API is performed via Bearer auth. Provide your API key as the bearer token in the `Authorization` header:


    ```bash

    curl https://api.cavuno.com/v1/jobs \

    -H "Authorization: Bearer YOUR_SECRET_API_KEY"

    ```


    API requests without authentication will fail. ## Rate limits


    The Cavuno API has rate limits in place to ensure stability and reliability. By default, API keys are limited to 100 requests per minute. If you exceed your limit, requests return an HTTP 429 response with a `Retry-After` header indicating when you can try again. If you have a use case that needs a higher limit, contact support. ## Idempotency


    The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. For example, if a request to create a job fails due to a network connection error, you can safely retry the request with the same idempotency key, and we''ll guarantee that only one job is created. To perform an idempotent request, provide an additional `Idempotency-Key` header on any `POST`, `PATCH`, or `DELETE` request:


    ```bash

    curl https://api.cavuno.com/v1/jobs \

    -X POST \

    -H "Authorization: Bearer cavuno_live_..." \

    -H "Idempotency-Key: $(uuidgen)" \

    -H "Content-Type: application/json" \

    -d ''{ "title": "Senior Engineer" }''

    ```


    ## Errors


    Cavuno uses conventional HTTP response codes to indicate the success or failure of an API request. In general: codes in the `2xx` range indicate success, codes in the `4xx` range indicate an error that failed given the information provided (e.g., a required parameter was omitted), and codes in the `5xx` range indicate an error with Cavuno''s servers (these are rare). Error responses include a JSON body with details:


    ```json

    {

    "error": {

    "code": "validation_bad_request",

    "message": "Field ''title'' is required.",

    "requestId": "req_..."

    }

    }

    ```


    Some errors carry an additional `details` field with structured context, such as per-field validation issues. ### Plan upgrade hints


    When an Operator API request is refused because of the board''s Cavuno plan, the error also carries an `upgrade` object. It names the capability that blocked the request, the cheapest self-serve plan that unlocks it (when that can be told), and the hosted billing endpoints that start the upgrade:


    ```json

    {

    "error": {

    "code": "settings_plan_required_for_branding_removal",

    "message": "Removing Cavuno branding requires a plan that includes branding removal.",

    "requestId": "req_...",

    "upgrade": {

    "capability": "canRemoveBranding",

    "requiredPlan": "basic",

    "checkout": { "method": "POST", "path": "/v1/billing/checkout" },

    "changePlan": { "method": "POST", "path": "/v1/billing/upgrade" }

    }

    }

    }

    ```


    Call `GET /v1/billing/subscription` first. With no active subscription, use `checkout`; with one, use `changePlan`. Send `{ "planKey": "" }` and give the returned `url` to a person: both endpoints return a hosted page where a person confirms the purchase. Nothing is charged until they do. Each `path` is relative to the API origin (`https://api.cavuno.com`), like `Location` headers and list `url` fields, so do not join it to a base URL that already ends in `/v1`.'
  contact:
    name: Cavuno
    url: https://cavuno.com
servers:
- url: https://api.cavuno.com/v1
  description: Production
security:
- bearerAuth: []
tags:
- name: Media
  description: Upload and manage logos and other binary assets.
paths:
  /media/upload:
    post:
      summary: Upload a media file
      description: Uploads a file via the unified media dispatcher. Send a multipart form with `file` (binary) and `purpose` (one of `board_logo`, `board_hero`, `account_avatar`, `company_logo`, or `blog_image`). Optionally include `resourceType` and `resourceId` to bind the upload to an owning resource. The request is idempotent when an `Idempotency-Key` header is supplied.
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                purpose:
                  type: string
                  enum:
                  - board_logo
                  - board_hero
                  - account_avatar
                  - company_logo
                  - blog_image
                resourceType:
                  type: string
                resourceId:
                  type: string
              required:
              - file
              - purpose
      responses:
        '201':
          description: Successful response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaUpload'
        '400':
          description: The `purpose` field is invalid, or the request was otherwise malformed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The caller lacks the permission required for the requested upload purpose.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The owning resource for the upload (`resourceId`) does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: The uploaded file exceeded the 5 MB size limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '415':
          description: The uploaded file's MIME type is not supported.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too many uploads. The limit is 30 per minute per account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-audience: operator
      tags:
      - Media
      operationId: uploadMedia
  /media/{id}:
    get:
      summary: Retrieve a media file
      description: Retrieves the metadata for a media file along with a fresh signed URL valid for fifteen minutes.
      parameters:
      - schema:
          type: string
          minLength: 1
          description: The Cavuno media object's `id` returned by `POST /v1/media/upload`.
        required: true
        description: The Cavuno media object's `id` returned by `POST /v1/media/upload`.
        example: media_01jxyz
        name: id
        in: path
      responses:
        '200':
          description: Successful response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaGet'
        '404':
          description: Media file not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-audience: operator
      tags:
      - Media
      operationId: getMedia
  /media/upload-intents:
    post:
      operationId: createMediaUploadIntent
      summary: Create a staged media upload intent
      description: Creates a short-lived direct-upload intent for media bytes that cannot travel through a JSON or code argument. POST the original file bytes to the returned uploadUrl, then complete the intent with the returned storageId.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MediaUploadIntentCreate'
      responses:
        '201':
          description: Upload intent created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaUploadIntent'
        '400':
          description: The upload metadata is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The caller lacks permission for this purpose.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: The declared file size exceeds the purpose limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '415':
          description: The declared MIME type is unsupported.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too many uploads.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-audience: operator
      tags:
      - Media
  /media/upload-intents/{intentId}/complete:
    post:
      operationId: completeMediaUploadIntent
      summary: Complete a staged media upload
      description: Verifies the staged object against the intent using storage-owned byte length and MIME metadata, processes it through the normal media pipeline, and returns the resulting media object.
      parameters:
      - schema:
          type: string
          minLength: 1
        required: true
        example: intent_01jxyz
        name: intentId
        in: path
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MediaUploadIntentComplete'
      responses:
        '201':
          description: Upload completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaUpload'
        '400':
          description: The staged byte length or MIME type does not match the intent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The caller lacks permission for this purpose.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The intent or staged object was not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The intent is already being completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: The staged file exceeds the purpose limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '415':
          description: The staged MIME type is unsupported.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too many uploads.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-audience: operator
      tags:
      - Media
components:
  schemas:
    MediaUpload:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the object. Use this value as the `{id}` path parameter for `GET /v1/media/{id}`.
        object:
          type: string
          enum:
          - media_upload
          description: String representing the object's type. Objects of the same type share the same value.
        url:
          type:
          - string
          - 'null'
          description: URL where the file can be downloaded. Permanent for files served from the assets domain; a signed URL for legacy files. Always set on the upload response; may be `null` on retrieval if the underlying blob has been deleted.
        urlExpiresAt:
          type:
          - string
          - 'null'
          description: Time at which the signed `url` expires (ISO 8601 datetime), or `null` when the `url` is permanent and never expires.
        mimeType:
          type: string
          description: MIME type of the uploaded file.
        sizeBytes:
          type: number
          description: Size of the uploaded file, in bytes.
        purpose:
          type: string
          enum:
          - board_logo
          - board_hero
          - account_avatar
          - company_logo
          - blog_image
          description: Resource type the file was uploaded for.
      required:
      - id
      - object
      - url
      - urlExpiresAt
      - mimeType
      - sizeBytes
      - purpose
    MediaUploadIntentCreate:
      type: object
      properties:
        filename:
          type: string
          minLength: 1
          maxLength: 255
        mimeType:
          type: string
          minLength: 1
          maxLength: 255
        sizeBytes:
          type: integer
          maximum: 10485760
          exclusiveMinimum: 0
        purpose:
          type: string
          enum:
          - board_logo
          - board_hero
          - account_avatar
          - company_logo
          - blog_image
        resourceType:
          type: string
          minLength: 1
          maxLength: 128
        resourceId:
          type: string
          minLength: 1
          maxLength: 512
      required:
      - filename
      - mimeType
      - sizeBytes
      - purpose
    MediaGet:
      allOf:
      - $ref: '#/components/schemas/MediaUpload'
      - type: object
        properties:
          uploadedAt:
            type: string
            description: Time at which the file was uploaded. ISO 8601 datetime.
          referencedBy:
            type: array
            items:
              type: object
              properties:
                resourceType:
                  type: string
                  description: Type of the resource referencing this file.
                resourceId:
                  type: string
                  description: Identifier of the resource referencing this file.
              required:
              - resourceType
              - resourceId
            description: Resources currently known to reference this file.
        required:
        - uploadedAt
        - referencedBy
    MediaUploadIntentComplete:
      type: object
      properties:
        stagingStorageId:
          type: string
          minLength: 1
          description: The storageId returned after POSTing the raw file to the intent uploadUrl.
      required:
      - stagingStorageId
    PlanUpgradeHint:
      type: object
      properties:
        capability:
          type: string
          enum:
          - activeJobsLimit
          - teamSeatLimit
          - canBePublic
          - canRemoveBranding
          - apiAccess
          description: The plan capability that blocked the request, named as in `GET /v1/billing/subscription` `capabilities`.
        requiredPlan:
          type: string
          enum:
          - starter
          - basic
          - grow
          - advanced
          - scale
          description: The cheapest self-serve plan that unlocks the action. Pass it as `planKey`. Omitted when it cannot be told without more information; read `GET /v1/billing/subscription` and pick a higher plan.
        checkout:
          type: object
          properties:
            method:
              type: string
              enum:
              - POST
            path:
              type: string
              enum:
              - /v1/billing/checkout
          required:
          - method
          - path
          description: Starts a hosted checkout when the board has no active subscription (for example during a trial).
        changePlan:
          type: object
          properties:
            method:
              type: string
              enum:
              - POST
            path:
              type: string
              enum:
              - /v1/billing/upgrade
          required:
          - method
          - path
          description: Starts a hosted plan change when the board already has an active subscription.
      required:
      - capability
      - checkout
      - changePlan
      description: 'Present only on Operator API errors caused by the board''s Cavuno plan. Read `GET /v1/billing/subscription` to choose between `checkout` and `changePlan`, call it with `{ "planKey": requiredPlan }`, and give the returned `url` to a person to confirm. Each `path` is relative to the API origin, not to a `/v1` base URL. Both endpoints need `billing.manage`. Board API errors never include it.'
    MediaUploadIntent:
      type: object
      properties:
        id:
          type: string
          description: Opaque staged media upload intent identifier.
        object:
          type: string
          enum:
          - media_upload_intent
        uploadUrl:
          type: string
          format: uri
          description: Short-lived URL that accepts the original raw file bytes.
        expiresAt:
          type: string
          format: date-time
      required:
      - id
      - object
      - uploadUrl
      - expiresAt
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Machine-readable error code, such as `validation_bad_request` or `jobs_not_found`.
            message:
              type: string
              description: Human-readable explanation.
            requestId:
              type: string
              description: Unique id for this request. Include it when contacting support.
            details:
              description: Structured context for some errors, such as per-field validation issues.
            upgrade:
              $ref: '#/components/schemas/PlanUpgradeHint'
          required:
          - code
          - message
          - requestId
      required:
      - error
      description: The error envelope returned by every non-2xx response.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: cavuno_live_<keyId>_<secret>
      description: Use your secret API key to authenticate. Pass it as a Bearer token in the `Authorization` header. You can view and manage your API keys in the Cavuno dashboard.
externalDocs:
  description: Cavuno API reference
  url: https://cavuno.com/docs/api