> ## Documentation Index
> Fetch the complete documentation index at: https://docs.matambaintelligence.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send a document

> Sends one of the application's four documents to the broker: the file itself as the body, a JPEG or PNG smaller than 1,000,000 bytes and at most 8,000 pixels wide and high. We check that the file is whole, send it to the broker in the same request, and keep no copy. The same file sent again once the broker has it isn't sent twice; one whose earlier answer was unconfirmed is sent again. A different file for a type the broker has, or whose earlier file is unconfirmed, is refused. At most two of your documents are on their way to the broker at once. Send documents while the application is `documents_required` or `submitted`; the fourth makes it `submitted`. Requires the `apply` [scope](/keys-and-security#scopes).



## OpenAPI

````yaml /openapi.json put /v1/applications/{id}/documents/{type}
openapi: 3.1.0
info:
  title: Matamba Gateway
  version: '1'
  contact:
    name: Matamba Gateway partner support
    email: partners@matambaintelligence.com
    url: https://docs.matambaintelligence.com/support
  description: >-
    Open brokerage accounts for your customers, fund them from your wallet,
    place and track orders, and read each account's records at the broker.
    Amounts are integers in kobo. A field ending in `_kobo_decimal` is a decimal
    string of kobo, exact: digits, a point and at most 12 places, with a leading
    minus where an account can owe, and never an exponent. A whole-kobo figure
    beside one is it rounded in the direction its description says. Every error
    includes a `code` you can use in your logic. A list of values, such as an
    order state or an error `code`, can gain values: if you generate a client,
    have it accept values it doesn't know (in OpenAPI Generator,
    `enumUnknownDefaultCase`).
servers:
  - url: https://gateway-sandbox.matambaintelligence.com
    description: Sandbox
security:
  - bearer: []
tags:
  - name: Accounts
    description: The accounts you can trade for, and the broker's records for each one.
  - name: Orders
    description: >-
      Estimate, place, retrieve and cancel orders. We store each order before we
      send it to the exchange, and we send it only once.
  - name: Events
    description: >-
      Each change to your orders, applications and allocations creates an event.
      We send the same event bodies to your webhook endpoint. See
      [Webhooks](/webhooks) for how to verify them.
  - name: Applications
    description: Open a brokerage account for your customer.
  - name: Reference
    description: Code lists from the broker that you use in account applications.
  - name: Wallet
    description: >-
      Your wallet, its ledger, and the allocations you make from it to your
      customers' accounts.
  - name: Limits
    description: >-
      What you may send: the limits on your requests and your day, and how much
      of each you've used.
  - name: Keys
    description: Revoke a key that has leaked, yourself, at any hour.
paths:
  /v1/applications/{id}/documents/{type}:
    put:
      tags:
        - Applications
      summary: Send a document
      description: >-
        Sends one of the application's four documents to the broker: the file
        itself as the body, a JPEG or PNG smaller than 1,000,000 bytes and at
        most 8,000 pixels wide and high. We check that the file is whole, send
        it to the broker in the same request, and keep no copy. The same file
        sent again once the broker has it isn't sent twice; one whose earlier
        answer was unconfirmed is sent again. A different file for a type the
        broker has, or whose earlier file is unconfirmed, is refused. At most
        two of your documents are on their way to the broker at once. Send
        documents while the application is `documents_required` or `submitted`;
        the fourth makes it `submitted`. Requires the `apply`
        [scope](/keys-and-security#scopes).
      operationId: sendDocument
      parameters:
        - $ref: '#/components/parameters/ApplicationIdParameter'
        - $ref: '#/components/parameters/DocumentTypeParameter'
      requestBody:
        required: true
        description: The file itself.
        content:
          image/jpeg:
            schema:
              type: string
              format: binary
          image/png:
            schema:
              type: string
              format: binary
      responses:
        '200':
          $ref: '#/components/responses/DocumentResponse'
        '400':
          $ref: '#/components/responses/error.invalid_request'
          description: >-
            `invalid_request`: the file is empty, `type` isn't one of the four,
            or the body didn't arrive whole within 30 seconds.
        '401':
          $ref: '#/components/responses/error.unauthorized'
          description: '`unauthorized`'
        '403':
          $ref: '#/components/responses/error.feature_not_enabled.insufficient_scope'
          description: >-
            `insufficient_scope`: this key doesn't have the `apply` scope.
            `feature_not_enabled`: account opening isn't enabled on this
            gateway. Nothing was sent. [Contact us](/support).
        '404':
          $ref: '#/components/responses/error.application_not_found'
          description: '`application_not_found`'
        '409':
          $ref: >-
            #/components/responses/error.application_not_accepting_documents.document_already_delivered.document_in_flight.earlier_document_unconfirmed
          description: >-
            `application_not_accepting_documents`, `document_already_delivered`,
            `document_in_flight` or `earlier_document_unconfirmed`
        '413':
          $ref: '#/components/responses/error.document_too_large'
          description: '`document_too_large`'
        '415':
          $ref: '#/components/responses/error.unsupported_media_type'
          description: '`unsupported_media_type`: send `image/jpeg` or `image/png`.'
        '422':
          $ref: '#/components/responses/error.document_rejected.invalid_document'
          description: '`invalid_document` or `document_rejected`'
        '429':
          $ref: '#/components/responses/error.rate_limited'
          description: '`rate_limited`'
        '500':
          $ref: '#/components/responses/error.internal_error'
          description: '`internal_error`'
        '503':
          $ref: >-
            #/components/responses/error.document_unconfirmed.exchange_unavailable.service_unavailable.trading_paused
          description: >-
            `document_unconfirmed`, `exchange_unavailable`,
            `service_unavailable` or `trading_paused`
        default:
          $ref: '#/components/responses/ErrorResponse'
      security:
        - bearer:
            - apply
components:
  parameters:
    ApplicationIdParameter:
      name: id
      in: path
      required: true
      description: The application's `id`.
      schema:
        type: string
        pattern: ^app_[a-z2-7]{20}$
      example: app_3rbw6yq2kd5mz7tcxf4n
    DocumentTypeParameter:
      name: type
      in: path
      required: true
      description: Which of the four documents.
      schema:
        $ref: '#/components/schemas/DocumentType'
      example: government_id
  responses:
    DocumentResponse:
      description: The document, as the broker has it.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Document'
          example:
            object: document
            application: app_3rbw6yq2kd5mz7tcxf4n
            type: government_id
            state: delivered
            created_at: '2026-09-30T10:02:14Z'
            updated_at: '2026-09-30T10:02:14Z'
    error.invalid_request:
      description: 'An error: `invalid_request`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalid_request:
              summary: invalid_request
              value:
                error:
                  type: invalid_request_error
                  code: invalid_request
                  message: The request could not be read.
                  doc_url: https://docs.matambaintelligence.com/errors#invalid_request
    error.unauthorized:
      description: 'An error: `unauthorized`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
        WWW-Authenticate:
          $ref: '#/components/headers/WWWAuthenticateHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            unauthorized:
              summary: unauthorized
              value:
                error:
                  type: authentication_error
                  code: unauthorized
                  message: Invalid credentials.
                  doc_url: https://docs.matambaintelligence.com/errors#unauthorized
    error.feature_not_enabled.insufficient_scope:
      description: 'An error: `feature_not_enabled`, `insufficient_scope`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            feature_not_enabled:
              summary: feature_not_enabled
              value:
                error:
                  type: permission_error
                  code: feature_not_enabled
                  message: >-
                    This feature is not enabled on this gateway. Sending the
                    request again will not change the result. Contact us.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#feature_not_enabled
            insufficient_scope:
              summary: insufficient_scope
              value:
                error:
                  type: permission_error
                  code: insufficient_scope
                  message: >-
                    This API key does not have the scope this request requires.
                    Nothing was done.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#insufficient_scope
    error.application_not_found:
      description: 'An error: `application_not_found`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            application_not_found:
              summary: application_not_found
              value:
                error:
                  type: invalid_request_error
                  code: application_not_found
                  message: No such application.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#application_not_found
    error.application_not_accepting_documents.document_already_delivered.document_in_flight.earlier_document_unconfirmed:
      description: >-
        An error: `application_not_accepting_documents`,
        `document_already_delivered`, `document_in_flight`,
        `earlier_document_unconfirmed`.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
        Retry-After:
          $ref: '#/components/headers/RetryAfterHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            application_not_accepting_documents:
              summary: application_not_accepting_documents
              value:
                error:
                  type: invalid_request_error
                  code: application_not_accepting_documents
                  message: >-
                    This application does not take documents in its state.
                    Nothing was sent.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#application_not_accepting_documents
            document_already_delivered:
              summary: document_already_delivered
              value:
                error:
                  type: invalid_request_error
                  code: document_already_delivered
                  message: >-
                    The broker already has a different file of this type for
                    this application. Nothing was sent.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#document_already_delivered
            document_in_flight:
              summary: document_in_flight
              value:
                error:
                  type: invalid_request_error
                  code: document_in_flight
                  message: >-
                    This document is being sent to the broker. Send it again
                    shortly.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#document_in_flight
            earlier_document_unconfirmed:
              summary: earlier_document_unconfirmed
              value:
                error:
                  type: invalid_request_error
                  code: earlier_document_unconfirmed
                  message: >-
                    The broker did not confirm receipt of an earlier file of
                    this type. Nothing was sent. Send that earlier file again.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#earlier_document_unconfirmed
    error.document_too_large:
      description: 'An error: `document_too_large`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            document_too_large:
              summary: document_too_large
              value:
                error:
                  type: invalid_request_error
                  code: document_too_large
                  message: The document is 1,000,000 bytes or more. Nothing was sent.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#document_too_large
    error.unsupported_media_type:
      description: 'An error: `unsupported_media_type`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            unsupported_media_type:
              summary: unsupported_media_type
              value:
                error:
                  type: invalid_request_error
                  code: unsupported_media_type
                  message: Content-Type must be application/json.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#unsupported_media_type
    error.document_rejected.invalid_document:
      description: 'An error: `document_rejected`, `invalid_document`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            document_rejected:
              summary: document_rejected
              value:
                error:
                  type: application_error
                  code: document_rejected
                  message: >-
                    The broker refused this document. Nothing was delivered.
                    Contact us.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#document_rejected
            invalid_document:
              summary: invalid_document
              value:
                error:
                  type: invalid_request_error
                  code: invalid_document
                  message: >-
                    The file is not the image its Content-Type says, or is too
                    large to show. Nothing was sent.
                  doc_url: https://docs.matambaintelligence.com/errors#invalid_document
    error.rate_limited:
      description: 'An error: `rate_limited`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
        Retry-After:
          $ref: '#/components/headers/RetryAfterHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            rate_limited:
              summary: rate_limited
              value:
                error:
                  type: rate_limit_error
                  code: rate_limited
                  message: >-
                    Too many requests. Nothing was done. Send the same request
                    again after the Retry-After interval.
                  doc_url: https://docs.matambaintelligence.com/errors#rate_limited
    error.internal_error:
      description: 'An error: `internal_error`.'
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            internal_error:
              summary: internal_error
              value:
                error:
                  type: api_error
                  code: internal_error
                  message: >-
                    The gateway encountered an internal error. Send the same
                    request again, exactly as you sent it.
                  doc_url: https://docs.matambaintelligence.com/errors#internal_error
    error.document_unconfirmed.exchange_unavailable.service_unavailable.trading_paused:
      description: >-
        An error: `document_unconfirmed`, `exchange_unavailable`,
        `service_unavailable`, `trading_paused`.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
        Retry-After:
          $ref: '#/components/headers/RetryAfterHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            document_unconfirmed:
              summary: document_unconfirmed
              value:
                error:
                  type: api_error
                  code: document_unconfirmed
                  message: >-
                    Document unconfirmed: the broker did not confirm receipt of
                    the document. Send the same file again. Sending the same
                    file again is safe.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#document_unconfirmed
            exchange_unavailable:
              summary: exchange_unavailable
              value:
                error:
                  type: api_error
                  code: exchange_unavailable
                  message: >-
                    The broker cannot be reached. Nothing was written and
                    nothing was sent. Send the request again, with the same
                    Idempotency-Key if it has one.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#exchange_unavailable
            service_unavailable:
              summary: service_unavailable
              value:
                error:
                  type: api_error
                  code: service_unavailable
                  message: >-
                    The gateway is temporarily unable to process this request.
                    Send the same request again, with the same Idempotency-Key
                    if it has one.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#service_unavailable
            trading_paused:
              summary: trading_paused
              value:
                error:
                  type: api_error
                  code: trading_paused
                  message: >-
                    New orders, applications, documents and allocations are
                    paused. Nothing was written and nothing was sent. Cancels,
                    estimates and reads still work. Send it again after the
                    Retry-After interval.
                  doc_url: https://docs.matambaintelligence.com/errors#trading_paused
    ErrorResponse:
      description: >-
        An error. Use `error.code` in your logic. A path that doesn't exist
        returns 404 `not_found`, and a method the path doesn't support returns
        405 `method_not_allowed` with an `Allow` header.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestIdHeader'
        Cache-Control:
          $ref: '#/components/headers/CacheControlHeader'
        Retry-After:
          $ref: '#/components/headers/RetryAfterHeader'
        WWW-Authenticate:
          $ref: '#/components/headers/WWWAuthenticateHeader'
        Allow:
          $ref: '#/components/headers/AllowHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            not_found:
              summary: not_found
              value:
                error:
                  type: invalid_request_error
                  code: not_found
                  message: No such path. Check the path against the API reference.
                  doc_url: https://docs.matambaintelligence.com/errors#not_found
            method_not_allowed:
              summary: method_not_allowed
              value:
                error:
                  type: invalid_request_error
                  code: method_not_allowed
                  message: This method is not allowed on this path.
                  doc_url: >-
                    https://docs.matambaintelligence.com/errors#method_not_allowed
  schemas:
    DocumentType:
      title: DocumentType
      type: string
      enum:
        - photo
        - government_id
        - utility_bill
        - signature
      description: >-
        `photo`: a passport photograph. `government_id`: a government-issued ID.
        `utility_bill`: a utility bill, for the address. `signature`: a specimen
        of the customer's signature. New values can be added: handle an
        unrecognised value with a safe default.
    Document:
      type: object
      description: >-
        One document of an application, as the broker has it. The gateway keeps
        no copy of the file.
      required:
        - object
        - application
        - type
        - state
        - created_at
        - updated_at
      properties:
        object:
          type: string
          const: document
        application:
          type: string
          description: The application's `id`.
          example: app_3rbw6yq2kd5mz7tcxf4n
        type:
          $ref: '#/components/schemas/DocumentType'
        state:
          title: DocumentState
          type: string
          enum:
            - delivered
          description: >-
            `delivered`: the broker has the file. It doesn't mean the broker's
            staff have verified it. New values can be added: handle an
            unrecognised value with a safe default.
        created_at:
          type: string
          format: date-time
          description: When the document was first sent, in UTC.
        updated_at:
          type: string
          format: date-time
          description: When its state last changed, in UTC.
    Error:
      type: object
      description: The body of an error response.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
            - doc_url
          properties:
            type:
              title: ErrorType
              type: string
              description: >-
                The category of the error. New values can be added: handle an
                unrecognised value with a safe default.
              enum:
                - authentication_error
                - invalid_request_error
                - idempotency_error
                - order_error
                - application_error
                - wallet_error
                - limit_error
                - rate_limit_error
                - permission_error
                - api_error
            code:
              title: ErrorCode
              type: string
              description: >-
                The error code. Use it in your logic; it doesn't change. New
                values can be added: handle an unrecognised value with a safe
                default.
              enum:
                - unauthorized
                - not_found
                - method_not_allowed
                - unsupported_media_type
                - request_too_large
                - invalid_request
                - missing_required_field
                - unknown_account
                - duplicate_order
                - order_not_found
                - account_not_found
                - exchange_unavailable
                - order_not_sent
                - order_rejected
                - similar_order_unresolved
                - order_not_cancelable
                - cancel_unconfirmed
                - settlement_lockout
                - account_not_at_broker
                - exchange_error
                - feature_not_enabled
                - insufficient_scope
                - application_rejected
                - duplicate_application
                - application_not_found
                - application_not_sent
                - wallet_too_low
                - allocation_rejected
                - duplicate_allocation
                - allocation_not_found
                - allocation_not_sent
                - similar_allocation_unresolved
                - rate_limited
                - unknown_symbol
                - limit_exceeded
                - too_many_keys
                - service_unavailable
                - internal_error
                - trading_paused
                - outcome_not_recorded
                - document_too_large
                - invalid_document
                - application_not_accepting_documents
                - document_already_delivered
                - document_in_flight
                - earlier_document_unconfirmed
                - document_unconfirmed
                - document_rejected
            message:
              type: string
              description: >-
                A human-readable description of the error, for your logs. The
                wording can change.
            param:
              type: string
              description: >-
                The field, parameter or header that caused the error. Absent
                when the error isn't tied to a single field.
            reject_reason:
              type: string
              description: >-
                Why the exchange or broker rejected the request. Included with
                `order_rejected`, `application_rejected` and
                `allocation_rejected`, and takes the same values as the
                `reject_reason` field on the order, application or allocation.
            order:
              type: string
              description: >-
                The order the error is about, when it names one: the order that
                owns the `Idempotency-Key` for `duplicate_order`, the unresolved
                order for `similar_order_unresolved`, the order recorded for
                `order_rejected` and `order_not_sent`, and the order your
                request made for `outcome_not_recorded`.
              pattern: ^ord_[a-z2-7]{20}$
            application:
              type: string
              description: >-
                The application the error is about, when it names one: the one
                that owns the key for `duplicate_application`, the one recorded
                for `application_rejected` and `application_not_sent`, and the
                one your request made for `outcome_not_recorded`.
              pattern: ^app_[a-z2-7]{20}$
            allocation:
              type: string
              description: >-
                The allocation the error is about, when it names one: the one
                that owns the key for `duplicate_allocation`, the unresolved one
                for `similar_allocation_unresolved`, the one recorded for
                `allocation_rejected`, `allocation_not_sent` and
                `feature_not_enabled`, and the one your request made for
                `outcome_not_recorded`.
              pattern: ^alc_[a-z2-7]{20}$
            doc_url:
              type: string
              format: uri
              description: A link to the documentation for this error code.
          description: What went wrong, and the code to act on.
  headers:
    RequestIdHeader:
      description: >-
        A unique identifier for this request. Include it when you [contact
        us](/support#report-a-problem).
      schema:
        type: string
      example: req_ih4pqm3vb3uruahh
    CacheControlHeader:
      description: Always `no-store`.
      schema:
        type: string
        const: no-store
      example: no-store
    WWWAuthenticateHeader:
      description: 'Sent with 401: `Bearer realm="Matamba Gateway"`.'
      schema:
        type: string
      example: Bearer realm="Matamba Gateway"
    RetryAfterHeader:
      description: >-
        The number of seconds to wait before you retry. Sent with `409
        document_in_flight` (`1`), `429 rate_limited` (`1`), `503
        settlement_lockout` (`60`) and `503 trading_paused` (`60`).
      schema:
        type: integer
      example: 1
    AllowHeader:
      description: Sent with 405. Lists the methods the path supports.
      schema:
        type: string
      example: GET, POST
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: >-
        `Authorization: Bearer <key>`. Sandbox keys start with `mgw_test_` and
        live keys start with `mgw_live_`. Each key works only in its own
        environment, and a live key works only from the IP addresses or ranges
        registered for it.

````