mails-ai Labels API

Label objects: a name and a colour, applied to threads.

Operations 5

GET /v1/labels List labels #
POST /v1/labels Create a label #
GET /v1/labels/{id} Retrieve a label #
PATCH /v1/labels/{id} Update a label #
DELETE /v1/labels/{id} Delete a label #

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/mails-ai:mails-ai-labels-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

mails-ai-labels-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Mails.ai Labels API
  version: 0.2.0
  description: 'The Mails.ai API gives AI agents a real email identity: send and receive

    transactional email. Mail received within your plan''s limits is scanned for prompt injection and

    reaches you as a typed event. With classification turned on (a paid-plan feature), new mail can also

    be read for intent; a reply in a thread never is.


    ## Authentication

    All endpoints take a Bearer API key:


    ```

    Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    ```


    Keys carry one or more scopes — `send`, `read`, `draft` (writes drafts, but can neither send nor

    schedule one) and `manage` — and a mode: **live** (`mk_live_…`) or **test** (`mk_test_…`).


    ## Test mode

    A `mk_test_` key exercises the entire API — real validation, persisted resources, real

    `message.sent`/`*.received` events and webhooks — without sending real email or incurring cost. Build and

    test your whole integration on a test key, then flip one character to `mk_live_` to go live.

    `POST /v1/test/inbound` (test key only) lets you simulate inbound mail end-to-end.


    ## Idempotency

    Send endpoints accept an `Idempotency-Key` header; a repeated key replays the stored response instead of

    sending twice, with an `Idempotent-Replay: true` header.


    ## Pagination

    List endpoints are cursor-paginated: pass `limit` (1–100) and the `next_cursor` from the previous page.


    ## Errors

    Errors use a stable envelope: `{ "error": { "type", "code", "message", "param", "request_id" } }`. Every

    response carries an `X-Request-Id` header for support correlation.'
  contact:
    name: Mails.ai Support
    url: https://mails.ai
    email: support@mails.ai
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
- url: https://api.mails.ai
  description: Production
security:
- bearerAuth: []
tags:
- name: Labels
  description: 'Label objects: a name and a colour, applied to threads.'
paths:
  /v1/labels:
    get:
      tags:
      - Labels
      summary: List labels
      operationId: listLabels
      description: '**Requires scope:** `read`. Every label in the workspace (at most 200), by name.'
      responses:
        '200':
          description: The workspace's labels.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Label'
                    description: Every label in the workspace, sorted by name; a workspace has at most 200.
                  has_more:
                    type: boolean
                    description: 'Always `false`: every label comes in one response.'
                  next_cursor:
                    type: string
                    description: Pass as `cursor` to fetch the next page. Absent on the last page.
                required:
                - data
                - has_more
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-required-scope: read
    post:
      tags:
      - Labels
      summary: Create a label
      operationId: createLabel
      description: '**Requires scope:** `manage` or `inbox` (`inbox` only in a signed-in dashboard session; no API key or app can hold it). A name (unique in the workspace, ignoring case) and a colour from a fixed palette of 12.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLabelRequest'
            example:
              name: Invoices
              color: green
      responses:
        '201':
          description: The created label.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Label'
        '400':
          description: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'Conflict — duplicate resource, an in-progress idempotent request, a draft or scheduled message that started sending while it was being changed, or a thread deleted for good while one of its messages is being sent (`duplicate_resource`); or an agent name more than one agent has (`agent_name_conflict`: use the agent''s id); or a status change on an archived agent, since archiving cannot be undone (`agent_archived`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-required-scope: manage
      x-accepted-scopes:
      - manage
      - inbox
      x-session-scopes:
      - inbox
  /v1/labels/{id}:
    get:
      tags:
      - Labels
      summary: Retrieve a label
      operationId: getLabel
      description: '**Requires scope:** `read`.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Label id (`lbl_…`).
      responses:
        '200':
          description: The label.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Label'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-required-scope: read
    patch:
      tags:
      - Labels
      summary: Update a label
      operationId: updateLabel
      description: '**Requires scope:** `manage` or `inbox` (`inbox` only in a signed-in dashboard session; no API key or app can hold it). Renaming a label renames it on every thread that carries it.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Label id (`lbl_…`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateLabelRequest'
            example:
              color: blue
      responses:
        '200':
          description: The updated label.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Label'
        '400':
          description: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: 'Conflict — duplicate resource, an in-progress idempotent request, a draft or scheduled message that started sending while it was being changed, or a thread deleted for good while one of its messages is being sent (`duplicate_resource`); or an agent name more than one agent has (`agent_name_conflict`: use the agent''s id); or a status change on an archived agent, since archiving cannot be undone (`agent_archived`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-required-scope: manage
      x-accepted-scopes:
      - manage
      - inbox
      x-session-scopes:
      - inbox
    delete:
      tags:
      - Labels
      summary: Delete a label
      operationId: deleteLabel
      description: '**Requires scope:** `manage` or `inbox` (`inbox` only in a signed-in dashboard session; no API key or app can hold it). Deletes the label and takes it off every thread that carries it.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Label id (`lbl_…`).
      responses:
        '200':
          description: The deleted label's id.
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: The deleted label's id (`lbl_…`).
                  deleted:
                    type: boolean
                    description: 'Always `true`: the label is deleted, and its name is taken off every thread that carried it.'
                required:
                - id
                - deleted
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-required-scope: manage
      x-accepted-scopes:
      - manage
      - inbox
      x-session-scopes:
      - inbox
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              type: string
              enum:
              - invalid_request_error
              - authentication_error
              - permission_error
              - rate_limit_error
              - resource_error
              - payment_error
              - abuse_error
              - api_error
              description: High-level error category.
            code:
              type: string
              enum:
              - invalid_field
              - missing_field
              - missing_param
              - invalid_param_value
              - method_not_allowed
              - invalid_idempotency_key
              - duplicate_resource
              - slug_invalid
              - slug_reserved
              - slug_taken
              - agent_name_conflict
              - body_too_large
              - missing_authorization
              - missing_api_key
              - invalid_api_key
              - expired_api_key
              - revoked_api_key
              - invalid_access_token
              - email_not_verified
              - insufficient_scope
              - connected_app_not_allowed
              - sso_required
              - workspace_mismatch
              - agent_not_owned
              - rate_limit_exceeded
              - daily_limit_exceeded
              - hourly_limit_exceeded
              - monthly_limit_exceeded
              - agent_not_found
              - agent_paused
              - agent_archived
              - resource_not_found
              - recipient_suppressed
              - recipient_not_allowed
              - domain_not_verified
              - ses_role_not_assumable
              - ses_role_external_id_not_required
              - ses_permission_denied
              - ses_setup_failed
              - ses_message_rejected
              - ses_events_not_confirmed
              - payment_required
              - payment_method_failed
              - subscription_canceled
              - billing_state_inconsistent
              - free_tier_exceeded
              - plan_limit_exceeded
              - cold_email_prohibited
              - agent_suspended
              - new_workspace_fanout_exceeded
              - resource_cap_exceeded
              - workspace_cap_exceeded
              - feature_not_enabled
              - test_mode_required
              - live_mode_required
              - unknown_test_address
              - workspace_not_approved
              - spam_pattern_detected
              - classifier_rejected
              - high_injection_score
              - complaint_threshold_exceeded
              - bounce_threshold_exceeded
              - internal_error
              - internal_server_error
              - upstream_error
              - upstream_unavailable
              - service_unavailable
              description: Stable machine-readable error code.
            message:
              type: string
              description: Human-readable explanation.
            param:
              type:
              - string
              - 'null'
              description: The offending request field, when applicable.
            request_id:
              type: string
              description: Echo of the X-Request-Id header for support correlation.
            errors:
              type: array
              items:
                $ref: '#/components/schemas/FieldError'
              description: On a validation failure, EVERY offending field (not just the first). The top-level code/message/param mirror errors[0] for backward compatibility.
            resets_at:
              type:
              - string
              - 'null'
              format: date-time
              description: 'On every 429: when the limit lets the request through again (UTC). Null when waiting will not help, for a cap that only an upgrade or a deletion lifts.'
            retry_after_seconds:
              type:
              - integer
              - 'null'
              description: 'On every 429: the seconds until `resets_at`, null when it is null. On any other error that says how long to wait, such as a 503 `upstream_unavailable`: the seconds its `Retry-After` header gives.'
            upgrade_url:
              type: string
              format: uri
              description: 'On every 402: the dashboard page where the plan can be changed, `https://app.mails.ai/billing`.'
          required:
          - type
          - code
          - message
          description: 'The error, as every error response carries it: `type`, `code`, `message`, `param` and `request_id`, plus `errors` on a validation failure, `resets_at` and `retry_after_seconds` on a 429, `retry_after_seconds` on any other error with a `Retry-After`, and `upgrade_url` on a 402. A failed item in a batch send is the same error, and `retry_after_seconds` is how it says how long to wait, since an item has no headers of its own.'
      required:
      - error
    CreateLabelRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
          description: Unique within the workspace, ignoring case. 1-64 characters.
        color:
          type: string
          enum:
          - gray
          - red
          - orange
          - amber
          - yellow
          - green
          - teal
          - cyan
          - blue
          - indigo
          - purple
          - pink
          default: gray
          description: The label's colour, one of 12 palette names. Left out, it is `gray`.
      required:
      - name
      additionalProperties: false
    Label:
      type: object
      properties:
        id:
          type: string
          description: Label id (`lbl_…`).
        name:
          type: string
          description: Unique in the workspace, ignoring case.
        color:
          type: string
          enum:
          - gray
          - red
          - orange
          - amber
          - yellow
          - green
          - teal
          - cyan
          - blue
          - indigo
          - purple
          - pink
          description: 'The label''s colour, one of 12 palette names: `gray` unless another was chosen.'
        created_at:
          type: string
          format: date-time
          description: When the label was created (UTC).
        updated_at:
          type: string
          format: date-time
          description: When the label was last changed with PATCH, even by a request that left it as it was. Equal to `created_at` on a label never patched.
      required:
      - id
      - name
      - color
      - created_at
      - updated_at
    UpdateLabelRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
          description: Renaming a label renames it on every thread that carries it.
        color:
          type: string
          enum:
          - gray
          - red
          - orange
          - amber
          - yellow
          - green
          - teal
          - cyan
          - blue
          - indigo
          - purple
          - pink
          description: A new colour from the same palette of 12. Left out, the colour stays as it is; a request must carry `name`, `color` or both.
      additionalProperties: false
    FieldError:
      type: object
      properties:
        code:
          type: string
          enum:
          - invalid_field
          - missing_field
          - missing_param
          - invalid_param_value
          - method_not_allowed
          - invalid_idempotency_key
          - duplicate_resource
          - slug_invalid
          - slug_reserved
          - slug_taken
          - agent_name_conflict
          - body_too_large
          - missing_authorization
          - missing_api_key
          - invalid_api_key
          - expired_api_key
          - revoked_api_key
          - invalid_access_token
          - email_not_verified
          - insufficient_scope
          - connected_app_not_allowed
          - sso_required
          - workspace_mismatch
          - agent_not_owned
          - rate_limit_exceeded
          - daily_limit_exceeded
          - hourly_limit_exceeded
          - monthly_limit_exceeded
          - agent_not_found
          - agent_paused
          - agent_archived
          - resource_not_found
          - recipient_suppressed
          - recipient_not_allowed
          - domain_not_verified
          - ses_role_not_assumable
          - ses_role_external_id_not_required
          - ses_permission_denied
          - ses_setup_failed
          - ses_message_rejected
          - ses_events_not_confirmed
          - payment_required
          - payment_method_failed
          - subscription_canceled
          - billing_state_inconsistent
          - free_tier_exceeded
          - plan_limit_exceeded
          - cold_email_prohibited
          - agent_suspended
          - new_workspace_fanout_exceeded
          - resource_cap_exceeded
          - workspace_cap_exceeded
          - feature_not_enabled
          - test_mode_required
          - live_mode_required
          - unknown_test_address
          - workspace_not_approved
          - spam_pattern_detected
          - classifier_rejected
          - high_injection_score
          - complaint_threshold_exceeded
          - bounce_threshold_exceeded
          - internal_error
          - internal_server_error
          - upstream_error
          - upstream_unavailable
          - service_unavailable
          description: Stable machine-readable code for this field.
        message:
          type: string
          description: Human-readable explanation for this field.
        param:
          type:
          - string
          - 'null'
          description: The offending request field (dot-path), or null.
      required:
      - code
      - message
      - param
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: mk_live_<32 hex>, mk_test_<32 hex>, or moa_<48 hex>
      description: 'A Mails.ai API key, or an OAuth access token (`moa_…`, valid for 1 hour) from signing in through an app such as the CLI, Claude or ChatGPT. OAuth discovery: https://api.mails.ai/.well-known/oauth-authorization-server and https://api.mails.ai/.well-known/oauth-protected-resource. An access token''s OAuth scope maps onto these API scopes: `full_access` = `send` + `read` + `manage` (not `draft`: the draft routes take those three too), `send` = `send` + `read`, `read` = `read`. Scopes (`send`/`read`/`manage`/`draft`) are noted per operation via `x-required-scope`; when more than one scope opens an operation (the draft routes also take `draft`), `x-accepted-scopes` lists them all. `inbox` appears there too, on the triage routes (changing and trashing threads, labels, cancelling a scheduled send): only a signed-in dashboard session holds it (a workspace Member''s), never an API key or OAuth token, and `x-session-scopes` names it.'