Primitive Account API

Manage your account settings, storage, and webhook secret

Operations 5

GET /account Get account info #
PATCH /account Update account settings #
GET /account/storage Get storage usage #
GET /account/webhook-secret Get webhook signing secret #
POST /account/webhook-secret/rotate Rotate webhook signing secret #

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/primitive-account-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

primitive-account-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Primitive Account API
  version: 1.0.0
  description: Primitive is email infrastructure for AI agents.
  contact:
    name: Primitive
    url: https://primitive.dev
  license:
    name: Proprietary
    url: https://primitive.dev/terms
  x-stability-level: stable
  x-deprecation-policy: 'Breaking changes are announced at least 6 months in advance. Deprecated fields carry x-deprecated: true. The current stable version is v1.'
servers:
- url: https://api.primitive.dev/v1
  description: Canonical API host (PRIMITIVE_API_BASE_URL). Carries every public API operation.
tags:
- name: Account
  description: Manage your account settings, storage, and webhook secret
paths:
  /account:
    get:
      operationId: getAccount
      summary: Get account info
      tags:
      - Account
      responses:
        '200':
          description: Account details
          content:
            application/json:
              schema:
                allOf:
                - type: object
                  properties:
                    success:
                      type: boolean
                      const: true
                  required:
                  - success
                  - data
                - type: object
                  properties:
                    data:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        email:
                          type: string
                        plan:
                          type: string
                        limits:
                          type: object
                          description: Plan-derived quota limits for an account.
                          properties:
                            storage_mb:
                              type: number
                            send_per_hour:
                              type: number
                            send_per_day:
                              type: number
                            api_per_minute:
                              type: number
                            webhooks_max_global:
                              type:
                              - number
                              - 'null'
                            webhooks_per_domain:
                              type: boolean
                            filters_per_domain:
                              type: boolean
                            spam_thresholds_per_domain:
                              type: boolean
                          required:
                          - storage_mb
                          - send_per_hour
                          - send_per_day
                          - api_per_minute
                          - webhooks_max_global
                          - webhooks_per_domain
                          - filters_per_domain
                          - spam_thresholds_per_domain
                        entitlements:
                          type: array
                          items:
                            type: string
                          description: 'Granted org entitlement keys (sorted). A headless caller reads its

                            capabilities here — e.g. an emailless agent seeing only

                            ["send_mail", "send_to_known_addresses"] knows it is reply-only.

                            '
                        managed_inbox_address:
                          type:
                          - string
                          - 'null'
                          description: The managed inbox FQDN to reply as, or null if the org has no managed inbox.
                        created_at:
                          type: string
                          format: date-time
                        onboarding_completed:
                          type: boolean
                        onboarding_step:
                          type:
                          - string
                          - 'null'
                        stripe_subscription_status:
                          type:
                          - string
                          - 'null'
                        subscription_current_period_end:
                          type:
                          - string
                          - 'null'
                          format: date-time
                        subscription_cancel_at_period_end:
                          type:
                          - boolean
                          - 'null'
                        spam_threshold:
                          type:
                          - number
                          - 'null'
                          minimum: 0
                          maximum: 15
                        discard_content_on_webhook_confirmed:
                          type: boolean
                        webhook_secret_rotated_at:
                          type:
                          - string
                          - 'null'
                          format: date-time
                      required:
                      - id
                      - email
                      - plan
                      - limits
                      - entitlements
                      - managed_inbox_address
                      - created_at
                      - discard_content_on_webhook_confirmed
          headers:
            ratelimit-limit:
              description: Maximum number of requests allowed in the current window.
              schema:
                type: integer
                minimum: 1
                example: 120
            ratelimit-remaining:
              description: Remaining requests in the current window.
              schema:
                type: integer
                minimum: 0
                example: 118
            ratelimit-reset:
              description: Unix timestamp (seconds) when the current window resets.
              schema:
                type: integer
                example: 1700000060
            ratelimit-policy:
              description: Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.
              schema:
                type: string
                example: 120;w=60
        '401':
          $ref: '#/components/responses/Unauthorized'
          description: Invalid or missing API key
        '404':
          $ref: '#/components/responses/NotFound'
          description: Resource not found
      security:
      - BearerAuth: []
      description: 'Retrieve the authenticated organization''s account: organization identity, current plan, usage, and onboarding state.'
    patch:
      operationId: updateAccount
      summary: Update account settings
      tags:
      - Account
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                spam_threshold:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 15
                  description: Global spam score threshold (0-15). Emails scoring above this are rejected. Set to null to disable.
                discard_content_on_webhook_confirmed:
                  type: boolean
                  description: Whether to discard email content after the webhook endpoint confirms receipt.
              minProperties: 1
      responses:
        '200':
          description: Updated account
          content:
            application/json:
              schema:
                allOf:
                - type: object
                  properties:
                    success:
                      type: boolean
                      const: true
                  required:
                  - success
                  - data
                - type: object
                  properties:
                    data:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        email:
                          type: string
                        plan:
                          type: string
                        spam_threshold:
                          type:
                          - number
                          - 'null'
                          minimum: 0
                          maximum: 15
                        discard_content_on_webhook_confirmed:
                          type: boolean
                      required:
                      - id
                      - email
                      - plan
                      - discard_content_on_webhook_confirmed
          headers:
            ratelimit-limit:
              description: Maximum number of requests allowed in the current window.
              schema:
                type: integer
                minimum: 1
                example: 120
            ratelimit-remaining:
              description: Remaining requests in the current window.
              schema:
                type: integer
                minimum: 0
                example: 118
            ratelimit-reset:
              description: Unix timestamp (seconds) when the current window resets.
              schema:
                type: integer
                example: 1700000060
            ratelimit-policy:
              description: Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.
              schema:
                type: string
                example: 120;w=60
        '400':
          $ref: '#/components/responses/ValidationError'
          description: Invalid request parameters
        '401':
          $ref: '#/components/responses/Unauthorized'
          description: Invalid or missing API key
        '404':
          $ref: '#/components/responses/NotFound'
          description: Resource not found
      security:
      - BearerAuth: []
      description: Update the mutable account settings (such as display name and notification preferences) for the authenticated organization.
  /account/storage:
    get:
      operationId: getStorageStats
      summary: Get storage usage
      tags:
      - Account
      responses:
        '200':
          description: Storage statistics
          content:
            application/json:
              schema:
                allOf:
                - type: object
                  properties:
                    success:
                      type: boolean
                      const: true
                  required:
                  - success
                  - data
                - type: object
                  properties:
                    data:
                      type: object
                      properties:
                        used_bytes:
                          type: integer
                          description: Total storage used in bytes
                        used_kb:
                          type: number
                          description: Total storage used in kilobytes (1 decimal)
                        used_mb:
                          type: number
                          description: Total storage used in megabytes (2 decimals)
                        quota_mb:
                          type: number
                          description: Storage quota in megabytes (based on plan)
                        percentage:
                          type: number
                          description: Percentage of quota used (1 decimal)
                        emails_count:
                          type: integer
                          description: Number of stored emails
                      required:
                      - used_bytes
                      - used_kb
                      - used_mb
                      - quota_mb
                      - percentage
                      - emails_count
          headers:
            ratelimit-limit:
              description: Maximum number of requests allowed in the current window.
              schema:
                type: integer
                minimum: 1
                example: 120
            ratelimit-remaining:
              description: Remaining requests in the current window.
              schema:
                type: integer
                minimum: 0
                example: 118
            ratelimit-reset:
              description: Unix timestamp (seconds) when the current window resets.
              schema:
                type: integer
                example: 1700000060
            ratelimit-policy:
              description: Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.
              schema:
                type: string
                example: 120;w=60
        '401':
          $ref: '#/components/responses/Unauthorized'
          description: Invalid or missing API key
        '404':
          $ref: '#/components/responses/NotFound'
          description: Resource not found
      security:
      - BearerAuth: []
      description: Return stored-email storage usage and the remaining quota for the authenticated organization.
  /account/webhook-secret:
    get:
      operationId: getWebhookSecret
      summary: Get webhook signing secret
      description: 'Returns the webhook signing secret for your account. If no

        secret exists yet, one is generated automatically on first

        access.


        Signing is account-scoped, not per-endpoint. Every webhook

        delivery from any of your registered endpoints is signed

        with this single secret. Rotate via

        `POST /account/webhook-secret/rotate`.


        **Secret format**: the returned string looks base64-shaped

        (e.g. `XNHBBW8VqoBjRfNs1tkZj11jTk...`) but is NOT base64.

        Use it AS-IS as a UTF-8 string when computing HMAC over a

        delivery body. Base64-decoding before HMAC will silently

        produce mismatched signatures.


        See the API-level "Webhook signing" section for the full

        wire format (header name, signed string shape, hash algo,

        tolerance) including a language-agnostic verification

        recipe.'
      tags:
      - Account
      responses:
        '200':
          description: Webhook secret
          content:
            application/json:
              schema:
                allOf:
                - type: object
                  properties:
                    success:
                      type: boolean
                      const: true
                  required:
                  - success
                  - data
                - type: object
                  properties:
                    data:
                      type: object
                      properties:
                        secret:
                          type: string
                          description: The webhook signing secret value
                      required:
                      - secret
          headers:
            ratelimit-limit:
              description: Maximum number of requests allowed in the current window.
              schema:
                type: integer
                minimum: 1
                example: 120
            ratelimit-remaining:
              description: Remaining requests in the current window.
              schema:
                type: integer
                minimum: 0
                example: 118
            ratelimit-reset:
              description: Unix timestamp (seconds) when the current window resets.
              schema:
                type: integer
                example: 1700000060
            ratelimit-policy:
              description: Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.
              schema:
                type: string
                example: 120;w=60
        '401':
          $ref: '#/components/responses/Unauthorized'
          description: Invalid or missing API key
        '404':
          $ref: '#/components/responses/NotFound'
          description: Resource not found
      security:
      - BearerAuth: []
  /account/webhook-secret/rotate:
    post:
      operationId: rotateWebhookSecret
      summary: Rotate webhook signing secret
      description: 'Generates a new webhook signing secret, replacing the current one.

        Rate limited to once per 60 minutes.'
      tags:
      - Account
      responses:
        '200':
          description: New webhook secret
          content:
            application/json:
              schema:
                allOf:
                - type: object
                  properties:
                    success:
                      type: boolean
                      const: true
                  required:
                  - success
                  - data
                - type: object
                  properties:
                    data:
                      type: object
                      properties:
                        secret:
                          type: string
                          description: The webhook signing secret value
                      required:
                      - secret
          headers:
            ratelimit-limit:
              description: Maximum number of requests allowed in the current window.
              schema:
                type: integer
                minimum: 1
                example: 120
            ratelimit-remaining:
              description: Remaining requests in the current window.
              schema:
                type: integer
                minimum: 0
                example: 118
            ratelimit-reset:
              description: Unix timestamp (seconds) when the current window resets.
              schema:
                type: integer
                example: 1700000060
            ratelimit-policy:
              description: Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.
              schema:
                type: string
                example: 120;w=60
        '400':
          $ref: '#/components/responses/ValidationError'
          description: Invalid request parameters
        '401':
          $ref: '#/components/responses/Unauthorized'
          description: Invalid or missing API key
        '404':
          $ref: '#/components/responses/NotFound'
          description: Resource not found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
      security:
      - BearerAuth: []
      parameters:
      - name: Idempotency-Key
        in: header
        required: false
        description: Optional client-supplied idempotency key. Retrying a request with the same key returns the original result instead of performing the action a second time; if omitted the server derives one from the canonical payload hash. Safe to retry network failures without duplicating side effects.
        schema:
          type: string
          minLength: 1
          maxLength: 255
components:
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: not_found
              message: Resource not found
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: unauthorized
              message: Invalid or missing API key
    ValidationError:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: validation_error
              message: Invalid domain format
    RateLimited:
      description: Rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: rate_limit_exceeded
              message: Rate limit exceeded
  schemas:
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          const: false
        error:
          type: object
          properties:
            code:
              type: string
              enum:
              - unauthorized
              - forbidden
              - not_found
              - validation_error
              - rate_limit_exceeded
              - internal_error
              - conflict
              - mx_conflict
              - outbound_disabled
              - cannot_send_from_domain
              - recipient_not_allowed
              - outbound_key_missing
              - outbound_unreachable
              - outbound_key_invalid
              - outbound_capacity_exhausted
              - outbound_response_malformed
              - outbound_relay_failed
              - discard_not_enabled
              - inbound_not_repliable
              - search_timeout
              - authorization_pending
              - slow_down
              - access_denied
              - expired_token
              - invalid_device_code
              - invalid_signup_code
              - invalid_signup_token
              - invalid_verification_code
              - email_delivery_failed
              - clerk_signup_failed
              - no_orgs_for_user
              - org_not_accessible
              - feature_disabled
              - memory_conflict
              - developer_usage_credit_exhausted
              - no_payout_address
              - ownership_proof_failed
              - payment_verification_failed
              - payment_declined
              - challenge_expired
              - settlement_failed
              - template_not_installable
              - scaffold_only
              - invalid_variables
              - unknown_secrets
              - missing_secrets
              - no_inbound_domain
              - domain_cannot_send
              - address_taken
              - route_cap_reached
              - name_exhausted
            message:
              type: string
            details:
              type: object
              description: 'Optional structured data that callers can inspect to recover

                from the error. The fields present depend on `code`. Additional

                keys may be added over time without a major-version bump.

                '
              additionalProperties: true
              properties:
                mx_conflict:
                  type: object
                  description: Present when `code == mx_conflict`.
                  required:
                  - provider_name
                  - suggested_subdomain
                  properties:
                    provider_name:
                      type: string
                      description: Human-readable name of the detected mailbox provider (e.g. "Google Workspace").
                    suggested_subdomain:
                      type: string
                      description: Subdomain to try instead (e.g. "mail" for `mail.example.com`).
                required_entitlements:
                  type: array
                  items:
                    type: string
                  description: Entitlements that would allow a denied send when no recipient-scope gate was granted.
                sent_email_id:
                  type: string
                  description: ID of the persisted sent-email attempt associated with the error.
                content_hash:
                  type: string
                  description: Content hash of the original request on idempotency cache-hit errors.
                client_idempotency_key:
                  type: string
                  description: Effective idempotency key associated with the original request.
            gates:
              type: array
              items:
                $ref: '#/components/schemas/GateDenial'
              description: Structured per-gate denial detail for recipient-scope send-mail failures.
            request_id:
              type: string
              description: Server-issued request identifier for support and tracing.
          required:
          - code
          - message
      required:
      - success
      - error
    GateDenial:
      type: object
      properties:
        name:
          type: string
          enum:
          - send_to_confirmed_domains
          - send_to_known_addresses
          description: Public recipient-scope gate name that denied the send.
        reason:
          type: string
          enum:
          - domain_not_confirmed
          - recipient_unauthenticated
          - recipient_not_known
          description: Stable machine-readable denial reason.
        message:
          type: string
          description: Human-readable explanation of the gate denial.
        subject:
          type: string
          description: Domain or address the gate evaluated.
        fix:
          $ref: '#/components/schemas/GateFix'
        docs_url:
          type: string
          description: Public docs URL with more context.
      required:
      - name
      - reason
      - message
      - subject
    GateFix:
      type: object
      properties:
        action:
          type: string
          enum:
          - confirm_domain
          - sender_must_fix_authentication
          - wait_for_inbound
          description: Suggested next action for the caller.
        subject:
          type: string
          description: Entity the action applies to.
      required:
      - action
      - subject
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: 'API key with `prim_` prefix or OAuth access token with `prim_oat_` prefix: `Authorization: Bearer <token>`. Access is governed by the caller''s organization role (`owner`, `admin`, or `member`): API keys always act at `member` level regardless of who created them, and OAuth access tokens act with the authorizing user''s current organization role, resolved per request. Every operation in this spec is available to organization members; billing and organization administration are owner/admin actions performed in the dashboard and are not part of this API.'
    DownloadToken:
      type: apiKey
      in: query
      name: token
      description: Signed download token provided in webhook payloads