> ## Documentation Index
> Fetch the complete documentation index at: https://developers.1-funnel.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit an individual SMS

> Durably accept an individual SMS for asynchronous processing (ADR-018 SMS-01).
`202` is not delivery confirmation. Requires `Idempotency-Key` (DEC-SMS-I01).




## OpenAPI

````yaml /specs/external-integration-api.openapi.yaml post /v1/businesses/{businessId}/sms/messages
openapi: 3.1.0
info:
  title: 1Funnel External Integration API
  version: 0.1.0-draft
  summary: External Integration API — Developer Preview (contract only, non-GA).
  description: |
    OpenAPI 3.1 for the **1Funnel External Integration API** (foundation through
    webhooks). Companion AsyncAPI documents outbound webhook event payloads.

    ## Status (read carefully)

    | Layer | Status |
    |-------|--------|
    | Architecture (Platform ADRs / STD-API-01) | Approved |
    | This OpenAPI document | **Developer Preview — contract only** (non-GA) |
    | Sandbox API host | Architecture **target** — not claimed operational |
    | Production API host | Architecture **target** — not claimed operational |

    This specification is published for integrator review. Documented endpoints
    and authentication services are **not** available for public integration.
    Sandbox and production availability will be announced separately. This is
    not general availability (ADR-011 DEC-5A-07 Preview API documentation).

    ## Authentication and authorization

    Callers authenticate with OAuth 2.0 Client Credentials
    (`client_secret_basic`) against the external authorization server
    (ADR-015, ADR-023). Access tokens must present audience
    `1funnel-external-api`.

    After token validation, every business-scoped operation requires:

    1. Valid application identity
    2. Active application-to-business grant for `{businessId}`
    3. Required resource permission (ADR-022)
    4. Resource ownership / isolation (ADR-016)

    `{businessId}` is a selector, not proof. OAuth scopes (when introduced) are
    coarse token vocabulary and are **not** the ADR-022 permission catalogue.
    Operations document required permissions with `x-required-permissions`.

    ## Servers and OAuth URLs

    API `servers` and OAuth token URLs are environment-specific architecture
    targets (ADR-023). OpenAPI cannot automatically switch the OAuth
    `tokenUrl` when a client selects a `servers` entry. See
    `x-1funnel-oauth` and the security scheme description.
  contact:
    name: 1Funnel Platform
    email: support@1funnel.ng
  license:
    name: Proprietary
    url: https://1funnel.ng
servers:
  - url: https://api.1-funnel.org
    description: |
      Production External Integration API host (ADR-023 target).
      Not claimed deployed or generally available.
  - url: https://api.sandbox.1-funnel.org
    description: |
      Sandbox External Integration API host (ADR-023 target).
      Not claimed deployed or generally available.
security:
  - OAuth2ClientCredentials: []
tags:
  - name: Foundation
    description: Shared conventions and cross-cutting components.
  - name: SMS
    description: |
      Individual SMS, bulk SMS, reporting, and SMS templates (ADR-018).
      Public bulk resource is `/sms/bulk-messages`. There is no `/sms/batches`.
  - name: Wallet
    description: Read-only wallet balance (ADR-019).
  - name: OTP
    description: |
      Managed OTP challenges (ADR-020 / ADR-008). Secrets are never returned.
      Service availability is not claimed by this draft.
  - name: Webhooks
    description: |
      Webhook endpoint management, event history, and delivery inspection
      (ADR-021). Signature protocol DEC-WH-S01 approved. Ownership
      verification deferred in v1. Public manual replay and public secret
      rotation are not available. See WEBHOOK-DECISION-REGISTER.md.
paths:
  /v1/businesses/{businessId}/sms/messages:
    parameters:
      - $ref: '#/components/parameters/BusinessId'
    post:
      tags:
        - SMS
      summary: Submit an individual SMS
      description: >
        Durably accept an individual SMS for asynchronous processing (ADR-018
        SMS-01).

        `202` is not delivery confirmation. Requires `Idempotency-Key`
        (DEC-SMS-I01).
      operationId: createSmsMessage
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyRequired'
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SmsMessageCreateRequest'
            examples:
              freeText:
                summary: Free-text transactional SMS
                value:
                  from: 1FUNNEL
                  to: '+2348012345678'
                  classification: transactional
                  message: Your order ORD-1001 is confirmed.
              templateResolved:
                summary: Template id (active revision pinned at acceptance)
                value:
                  from: 1FUNNEL
                  to: '+2348012345678'
                  classification: transactional
                  template_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
                  template_variables:
                    first_name: Ada
                    order_id: ORD-1001
      responses:
        '202':
          description: Durably accepted for asynchronous processing
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestIdResponse'
            Location:
              $ref: '#/components/headers/Location'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmsMessage'
              examples:
                accepted:
                  value:
                    id: 018f3c4e-7b2a-7c3d-8e9f-aaaaaaaaaaaa
                    business_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
                    from: 1FUNNEL
                    to: '+2348012345678'
                    classification: transactional
                    message: Your order ORD-1001 is confirmed.
                    status: queued
                    status_reason: null
                    template: null
                    accepted_at: '2026-10-13T09:00:00.000Z'
                    submitted_at: null
                    delivered_at: null
                    failed_at: null
                idempotentReplay:
                  summary: Same key and equivalent payload within seven days
                  value:
                    id: 018f3c4e-7b2a-7c3d-8e9f-aaaaaaaaaaaa
                    business_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
                    from: 1FUNNEL
                    to: '+2348012345678'
                    classification: transactional
                    message: Your order ORD-1001 is confirmed.
                    status: queued
                    status_reason: null
                    template: null
                    accepted_at: '2026-10-13T09:00:00.000Z'
                    submitted_at: null
                    delivered_at: null
                    failed_at: null
                templatePinned:
                  summary: Template submission with revision pin
                  value:
                    id: 018f3c4e-7b2a-7c3d-8e9f-aaaaaaaaaaaa
                    business_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
                    from: 1FUNNEL
                    to: '+2348012345678'
                    classification: transactional
                    message: Hi Ada, order ORD-1001 is confirmed.
                    status: queued
                    status_reason: null
                    template:
                      template_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
                      revision_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789cd
                    accepted_at: '2026-10-13T09:00:00.000Z'
                    submitted_at: null
                    delivered_at: null
                    failed_at: null
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableContent'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    BusinessId:
      name: businessId
      in: path
      required: true
      description: >
        Business resource selector in `/v1/businesses/{businessId}/…` (ADR-006).

        UUIDv7-compatible opaque identifier. `{businessId}` is **not**
        authorization

        proof. The resource server must independently verify an active

        application-to-business grant, required permission, and ownership
        (ADR-016,

        ADR-022).
      schema:
        $ref: '#/components/schemas/UuidV7'
      examples:
        grantedBusiness:
          summary: Example business id
          value: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
    IdempotencyKeyRequired:
      name: Idempotency-Key
      in: header
      required: true
      description: >
        Required for this designated state-changing operation (STD-API-01 D09,

        ADR-017 SECOP-05/06, DEC-SMS-I01 shared external idempotency model).


        Scope: `(application_id, business_id, operation, idempotency_key)`.


        Permanent uniqueness within scope; seven-day response replay for
        equivalent

        payloads; `409` `idempotency_conflict` on payload mismatch; reuse after

        replay expiry must never create a new operation. See the optional

        `Idempotency-Key` component description for concurrent and

        failed-before-acceptance rules.
      schema:
        type: string
        minLength: 1
        maxLength: 256
        examples:
          - idem_01HZX3K9EXAMPLE
    RequestId:
      name: X-Request-Id
      in: header
      required: false
      description: >
        Request correlation identifier (STD-API-01 D12). Clients may supply a
        value

        of 1–128 characters matching `A-Za-z0-9._-`. Missing or invalid values
        are

        replaced by a server-generated identifier. Distinct from W3C
        `traceparent`,

        resource ids, `Idempotency-Key`, and webhook event ids.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: ^[A-Za-z0-9._-]+$
        examples:
          - req_01HZX3K9EXAMPLE
  schemas:
    SmsMessageCreateRequest:
      type: object
      description: >
        Individual SMS submission (ADR-018 SMS-01 / SMS-09, DEC-SMS-N01 / T02).

        Provide exactly one of free-text `message` or `template_id`. Do not
        supply

        both. Clients must not supply authoritative segmentation or billing
        values.

        Template submissions resolve and pin the current active revision at
        durable

        acceptance; client-selected historical revisions are rejected.
      additionalProperties: false
      required:
        - from
        - to
        - classification
      properties:
        from:
          $ref: '#/components/schemas/SenderId'
          description: >
            Authorized sender identity. Backend validates authorization.

            Invalid sender formatting → `validation_failed`. Unauthorized sender
            →

            `sender_not_authorized` (403).
        to:
          $ref: '#/components/schemas/E164PhoneNumber'
        classification:
          $ref: '#/components/schemas/MessageClassification'
        message:
          type: string
          description: >
            Unicode direct message content (DEC-SMS-N01). Required when
            `template_id`

            is omitted. Segmentation is determined by the backend.
          minLength: 1
          maxLength: 4096
        template_id:
          $ref: '#/components/schemas/UuidV7'
          description: >
            Business-owned template. Active revision resolved and pinned at
            acceptance

            (DEC-SMS-T02). Archived or inactive templates →
            `template_not_active`.
        template_variables:
          $ref: '#/components/schemas/TemplateVariables'
      examples:
        - from: 1FUNNEL
          to: '+2348012345678'
          classification: transactional
          message: Your order ORD-1001 is confirmed.
        - from: 1FUNNEL
          to: '+2348012345678'
          classification: transactional
          template_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
          template_variables:
            first_name: Ada
            order_id: ORD-1001
    SmsMessage:
      type: object
      description: |
        Individual SMS resource. Acceptance is not delivery confirmation.
        Status is the merchant-visible display projection (ADR-018 SMS-12).
      additionalProperties: false
      required:
        - id
        - business_id
        - from
        - to
        - classification
        - status
        - accepted_at
      properties:
        id:
          $ref: '#/components/schemas/UuidV7'
        business_id:
          $ref: '#/components/schemas/UuidV7'
        from:
          $ref: '#/components/schemas/SenderId'
        to:
          $ref: '#/components/schemas/E164PhoneNumber'
        classification:
          $ref: '#/components/schemas/MessageClassification'
        message:
          type: string
          description: >-
            Effective message content after any template rendering at
            acceptance.
        status:
          $ref: '#/components/schemas/MessageStatus'
        status_reason:
          type:
            - string
            - 'null'
          description: Optional finer failure or state detail. Not a provider-native code.
        template:
          oneOf:
            - $ref: '#/components/schemas/TemplateRevisionPin'
            - type: 'null'
          description: Revision pinned at durable acceptance when template-based.
        accepted_at:
          $ref: '#/components/schemas/Timestamp'
          description: Durable acceptance timestamp (not provider submission or delivery).
        submitted_at:
          oneOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: 'null'
          description: Provider submission timestamp when known.
        delivered_at:
          oneOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: 'null'
          description: Delivery outcome timestamp when known.
        failed_at:
          oneOf:
            - $ref: '#/components/schemas/Timestamp'
            - type: 'null'
      examples:
        - id: 018f3c4e-7b2a-7c3d-8e9f-aaaaaaaaaaaa
          business_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
          from: 1FUNNEL
          to: '+2348012345678'
          classification: transactional
          message: Your order ORD-1001 is confirmed.
          status: delivered
          status_reason: null
          template: null
          accepted_at: '2026-10-13T09:00:00.000Z'
          submitted_at: '2026-10-13T09:00:01.000Z'
          delivered_at: '2026-10-13T09:00:05.000Z'
          failed_at: null
    UuidV7:
      type: string
      format: uuid
      pattern: >-
        ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$
      description: >
        UUID with version nibble `7` (UUIDv7). STD-API-01 prefers UUIDv7 for new

        platform-generated external resource identifiers. Clients must still
        treat

        the value as opaque. Not every path parameter is guaranteed to be v7
        solely

        because it is a UUID; use this schema where the contract asserts UUIDv7.
      examples:
        - 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
    SenderId:
      type: string
      description: >
        Authorized sender identity for the business (`from`). The backend
        validates

        that the application/business may use this sender. Arbitrary sender IDs
        are

        not permitted. Public sender-ID management resources remain future

        (ADR-018 SMS-19 / target architecture).
      minLength: 1
      maxLength: 20
      examples:
        - 1FUNNEL
    E164PhoneNumber:
      type: string
      description: >
        Recipient MSISDN in E.164 format (`+` followed by country code and
        subscriber

        number). Leading `+` required.
      pattern: ^\+[1-9]\d{7,14}$
      minLength: 9
      maxLength: 16
      examples:
        - '+2348012345678'
    MessageClassification:
      type: string
      description: |
        Public message classification (lowercase snake_case). Transactional vs
        promotional distinction for compliance and routing policy.
      enum:
        - transactional
        - promotional
      examples:
        - transactional
    TemplateVariables:
      type: object
      description: >
        Per-recipient or per-send template variables. Keys must match
        placeholders

        defined by the referenced template revision. Values are strings. Live
        OTP

        codes must not be supplied as template variables for the managed OTP
        product

        (ADR-008 / ADR-018 SMS-09).
      additionalProperties:
        type: string
        maxLength: 512
      examples:
        - first_name: Ada
          order_id: ORD-1001
    MessageStatus:
      type: string
      description: |
        Merchant-visible individual message status (ADR-018 SMS-12). Display
        projection — not bulk processing status and not raw provider codes.
      enum:
        - queued
        - sent
        - delivered
        - failed
      examples:
        - delivered
    TemplateRevisionPin:
      type: object
      description: >
        Immutable revision pin recorded on an accepted SMS (DEC-SMS-T02 /
        ADR-018

        SMS-08). Present on accepted message representations after the backend

        resolves the active revision at durable acceptance.
      additionalProperties: false
      required:
        - template_id
        - revision_id
      properties:
        template_id:
          $ref: '#/components/schemas/UuidV7'
        revision_id:
          $ref: '#/components/schemas/UuidV7'
      examples:
        - template_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789ab
          revision_id: 018f3c4e-7b2a-7c3d-8e9f-0123456789cd
    Timestamp:
      type: string
      format: date-time
      description: >
        RFC 3339 date-time. Response timestamps are UTC with a `Z` offset

        (STD-API-01 D06). Client-supplied timestamps must include an explicit
        offset;

        local times without an offset are rejected.
      examples:
        - '2026-10-13T09:00:00.000Z'
    ProblemDetails:
      type: object
      description: >
        RFC 9457 Problem Details for HTTP APIs (`application/problem+json`).

        STD-API-01 D08 requires `type`, `title`, `status`, `detail`, `code`, and

        `request_id`. `instance` is recommended. Validation failures include
        `errors`.


        Problem `type` namespace (DEC-SMS-E01):

        `https://developers.1-funnel.org/problems/{code}`

        These identifiers do not imply documentation pages are deployed.
        Resolvable

        problem-type documentation is required before GA.
      additionalProperties: true
      required:
        - type
        - title
        - status
        - detail
        - code
        - request_id
      properties:
        type:
          type: string
          format: uri-reference
          description: >-
            Problem class identifier using the developers.1-funnel.org
            namespace.
          examples:
            - https://developers.1-funnel.org/problems/validation_failed
        title:
          type: string
          description: Short, stable summary safe for clients.
          examples:
            - Validation failed
        status:
          type: integer
          minimum: 100
          maximum: 599
          description: HTTP status code for this occurrence.
          examples:
            - 400
        detail:
          type: string
          description: >-
            Occurrence-specific explanation. Must not include secrets or stack
            traces.
          examples:
            - The request failed validation.
        instance:
          type: string
          format: uri-reference
          description: URI reference for this occurrence (RFC 9457 SHOULD).
        code:
          $ref: '#/components/schemas/ProblemCode'
        request_id:
          type: string
          minLength: 1
          maxLength: 128
          pattern: ^[A-Za-z0-9._-]+$
          description: Same value as response header `X-Request-Id` (STD-API-01 MUST).
          examples:
            - req_01HZX3K9EXAMPLE
        errors:
          type: array
          description: >-
            Present for validation failures (STD-API-01). Each item has
            `pointer` and `code`.
          items:
            type: object
            additionalProperties: false
            required:
              - pointer
              - code
            properties:
              pointer:
                type: string
                description: JSON Pointer into the request body, or a query parameter name.
              code:
                type: string
                description: Stable field-level error code.
      examples:
        - type: https://developers.1-funnel.org/problems/validation_failed
          title: Validation failed
          status: 400
          detail: The request failed validation.
          instance: /v1/businesses/018f3c4e-7b2a-7c3d-8e9f-0123456789ab/sms/messages
          code: validation_failed
          request_id: req_01HZX3K9EXAMPLE
          errors:
            - pointer: /to
              code: field_invalid
    ProblemCode:
      type: string
      description: |
        Stable machine-readable Problem Details `code` values for the External
        Integration API. Type URI form:
        `https://developers.1-funnel.org/problems/{code}`.
        Resolvable problem-type documentation is required before GA; these
        identifiers do not imply pages are deployed today.
      enum:
        - validation_failed
        - authentication_required
        - permission_denied
        - resource_not_found
        - idempotency_conflict
        - recipient_limit_exceeded
        - sender_not_authorized
        - template_not_active
        - invalid_recipient
        - rate_limit_exceeded
        - service_unavailable
        - internal_error
        - balance_unavailable
        - otp_verification_failed
        - otp_challenge_expired
        - otp_challenge_locked
        - otp_challenge_consumed
        - otp_challenge_invalidated
        - otp_resend_cooldown
        - otp_resend_limit_exceeded
      examples:
        - validation_failed
        - otp_verification_failed
  headers:
    RequestIdResponse:
      description: >
        Correlation identifier for this response (STD-API-01 D12). Echoes a
        valid

        client `X-Request-Id` or a server-generated value.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: ^[A-Za-z0-9._-]+$
        examples:
          - req_01HZX3K9EXAMPLE
    Location:
      description: >
        URI of the created or accepted resource when a `Location` header applies

        (typically 201 or selected 202 responses). Capability contracts define
        when

        `Location` is present.
      schema:
        type: string
        format: uri-reference
    RetryAfter:
      description: >
        Hint for when the client may retry (for example 429 or 503). Value may
        be

        delay-seconds or an HTTP-date per RFC 9110.
      schema:
        type: string
        examples:
          - '60'
  responses:
    BadRequest:
      description: |
        Bad Request — malformed request or field validation failure
        (`code: validation_failed`, DEC-SMS-E01).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            validation:
              summary: Validation failure
              value:
                type: https://developers.1-funnel.org/problems/validation_failed
                title: Validation failed
                status: 400
                detail: One or more fields are invalid.
                code: validation_failed
                request_id: req_01HZX3K9EXAMPLE
                errors:
                  - pointer: /from
                    code: field_invalid
    Unauthorized:
      description: |
        Unauthorized — missing or invalid authentication
        (`code: authentication_required`, DEC-SMS-E01).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            authenticationRequired:
              value:
                type: >-
                  https://developers.1-funnel.org/problems/authentication_required
                title: Authentication required
                status: 401
                detail: A valid OAuth 2.0 access token is required.
                code: authentication_required
                request_id: req_01HZX3K9EXAMPLE
    Forbidden:
      description: >
        Forbidden — authenticated caller lacks required permission, business
        grant,

        or sender authorization (`permission_denied` or
        `sender_not_authorized`).

        Cross-business existence may be concealed with 404 instead (ADR-016).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            permissionDenied:
              value:
                type: https://developers.1-funnel.org/problems/permission_denied
                title: Forbidden
                status: 403
                detail: >-
                  The application is not permitted to perform this operation for
                  the selected business.
                code: permission_denied
                request_id: req_01HZX3K9EXAMPLE
            senderNotAuthorized:
              value:
                type: https://developers.1-funnel.org/problems/sender_not_authorized
                title: Sender not authorized
                status: 403
                detail: The sender identity is not authorized for this business.
                code: sender_not_authorized
                request_id: req_01HZX3K9EXAMPLE
    Conflict:
      description: >
        Conflict — state conflict or idempotency key reused with a different
        payload

        (STD-API-01 D08/D09).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            idempotencyConflict:
              summary: Idempotency key conflict
              value:
                type: https://developers.1-funnel.org/problems/idempotency_conflict
                title: Idempotency conflict
                status: 409
                detail: The Idempotency-Key was reused with a different payload.
                code: idempotency_conflict
                request_id: req_01HZX3K9EXAMPLE
    UnprocessableContent:
      description: >
        Unprocessable Content — syntactically valid request that cannot be
        processed

        due to semantic constraints (DEC-SMS-E01). Examples include recipient
        limit,

        inactive template, or invalid recipient.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            recipientLimit:
              summary: Bulk recipient limit exceeded
              value:
                type: >-
                  https://developers.1-funnel.org/problems/recipient_limit_exceeded
                title: Recipient limit exceeded
                status: 422
                detail: >-
                  The request exceeds the maximum of 1000 submitted recipient
                  entries.
                code: recipient_limit_exceeded
                request_id: req_01HZX3K9EXAMPLE
            templateNotActive:
              value:
                type: https://developers.1-funnel.org/problems/template_not_active
                title: Template not active
                status: 422
                detail: The template is archived or not active for new submissions.
                code: template_not_active
                request_id: req_01HZX3K9EXAMPLE
            invalidRecipient:
              value:
                type: https://developers.1-funnel.org/problems/invalid_recipient
                title: Invalid recipient
                status: 422
                detail: One or more recipients failed semantic validation.
                code: invalid_recipient
                request_id: req_01HZX3K9EXAMPLE
    TooManyRequests:
      description: |
        Too Many Requests — rate limit exceeded
        (`code: rate_limit_exceeded`, DEC-SMS-E01).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            rateLimited:
              value:
                type: https://developers.1-funnel.org/problems/rate_limit_exceeded
                title: Rate limit exceeded
                status: 429
                detail: The client has exceeded an applicable rate limit.
                code: rate_limit_exceeded
                request_id: req_01HZX3K9EXAMPLE
    InternalServerError:
      description: Internal Server Error — unexpected failure.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            internal:
              value:
                type: https://developers.1-funnel.org/problems/internal_error
                title: Internal server error
                status: 500
                detail: An unexpected error occurred.
                code: internal_error
                request_id: req_01HZX3K9EXAMPLE
    ServiceUnavailable:
      description: |
        Service Unavailable (`code: service_unavailable`, DEC-SMS-E01).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestIdResponse'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
          examples:
            unavailable:
              value:
                type: https://developers.1-funnel.org/problems/service_unavailable
                title: Service unavailable
                status: 503
                detail: The service is temporarily unavailable.
                code: service_unavailable
                request_id: req_01HZX3K9EXAMPLE
  securitySchemes:
    OAuth2ClientCredentials:
      type: oauth2
      description: >
        OAuth 2.0 Client Credentials for the External Integration API (ADR-015,
        ADR-023).


        Client authentication: HTTP Basic (`client_secret_basic`).

        Access-token audience: `1funnel-external-api`.


        The `tokenUrl` below is the **production** target. Sandbox uses a
        different

        host. OpenAPI cannot bind `tokenUrl` to the selected `servers` entry;
        see

        `x-1funnel-oauth` on the root document and the authentication guide when
        published.


        Coarse OAuth scopes (if any) are token-level vocabulary (ADR-013 IA-06).
        They

        are **not** the ADR-022 resource permission catalogue. Resource
        permissions

        are enforced after token validation via application-to-business grants

        (ADR-016) and are documented per operation with
        `x-required-permissions`.


        These URLs are architecture targets. They are not claimed to be deployed
        or

        generally available.
      flows:
        clientCredentials:
          tokenUrl: https://auth.1-funnel.org/oauth2/token
          scopes: {}
      x-1funnel-client-authentication: client_secret_basic
      x-1funnel-audience: 1funnel-external-api

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.