# Upload a KYC attachment

POST /customers/{customer_id}/kyc-attachmentsUpload a file for a KYC requirement

Endpoint: POST /customers/{customer_id}/kyc-attachments
Version: 2026-03-01
Security: oauth2

## Security:

  - `oauth2` (unknown)
    oauth2 scopes: kyc:upload

## Path parameters:

  - `customer_id` (string, required)
    Customer ID

## Header parameters:

  - `X-Idempotency-Key` (string)
    Unique string for idempotent POST requests. Cached for 24 hours.

## Request fields (multipart/form-data):

  - `evidence_type` (string, required)
    Evidence type to submit
    Enum: "cnh", "rg", "selfie", "proof_of_address", "ccmei", "ei_mei", "income_statement", "articles_of_association", "eireli_incorporation_statement", "email"

  - `requirement_id` (string, required)
    Format: `identity_{subject_id}`
    Example: identity_003XXXXXXXXXXXXXXX

  - `attachment_type` (string, required)
    Physical CNH: `front` and `back`. Digital CNH: `file` (single PDF)
    Enum: "front", "back", "file"

  - `file` (string, required)
    Binary file upload (JPEG, PNG for physical; PDF for digital)

  - `attachment_type` (string, required)
    RG: `front` and `back`
    Enum: "front", "back"

  - `file` (string, required)
    Binary file upload (JPEG, PNG)

  - `requirement_id` (string, required)
    Format: `selfie_{subject_id}`
    Example: selfie_003XXXXXXXXXXXXXXX

  - `attachment_type` (string, required)
    Attachment type
    Enum: "photo"

  - `requirement_id` (string, required)
    Format: `proof_of_address_{subject_id}`
    Example: proof_of_address_003XXXXXXXXXXXXXXX

  - `attachment_type` (string, required)
    Attachment type
    Enum: "file"

  - `file` (string, required)
    Binary file upload (PDF, JPEG, PNG)

  - `requirement_id` (string, required)
    Company document requirement identifier
    Example: company_document_001XXXXXXXXXXXXXXX

  - `requirement_id` (string, required)
    EI/MEI document requirement identifier
    Example: ei_mei_documents_001XXXXXXXXXXXXXXX

  - `attachment_type` (string, required)
    Two documents required: `ei_registration_requirement` and `ccmei`
    Enum: "ei_registration_requirement", "ccmei"

  - `requirement_id` (string, required)
    Revenue statement requirement identifier
    Example: income_statement_001XXXXXXXXXXXXXXX

  - `requirement_id` (string, required)
    Articles of association requirement identifier
    Example: articles_of_association_001XXXXXXXXXXXXXXX

  - `requirement_id` (string, required)
    EIRELI incorporation statement requirement identifier
    Example: eireli_incorporation_statement_001XXXXXXXXXXXXXXX

  - `requirement_id` (string, required)
    Format: `email_{subject_id}`
    Example: email_003XXXXXXXXXXXXXXX

  - `attachment_type` (string, required)
    Attachment type
    Enum: "email"

  - `value` (string, required)
    Email address for the co-owner (used for CCB digital signature)
    Example: co-owner@example.com

## Response 201:

  - `201` (unknown)
    Attachment uploaded

## Response 201 fields (application/json):

  - `attachment_type` (string, required)
    Echoes the slot just submitted
    Example: front

  - `submitted` (boolean, required)
    Always `true` on a successful upload — confirms the slot was filled

## Response 400:

  - `400` (unknown)
    Bad request

## Response 400 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/invalid-request"

  - `title` (string, required)
    Enum: "Invalid Request"

  - `status` (integer, required)
    Enum: "400"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "invalid_content_type", "missing_file", "missing_type", "file_too_large"

## Response 401:

  - `401` (unknown)
    Authentication failed

## Response 401 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/authentication-failed"

  - `title` (string, required)
    Enum: "Authentication Failed"

  - `status` (integer, required)
    Enum: "401"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "missing_token", "invalid_token", "token_expired"

## Response 403:

  - `403` (unknown)
    The credential is not permitted to perform this action

## Response 403 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/forbidden"

  - `title` (string, required)
    Enum: "Forbidden"

  - `status` (integer, required)
    Enum: "403"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "forbidden"

## Response 404:

  - `404` (unknown)
    Resource not found

## Response 404 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/not-found"

  - `title` (string, required)
    Enum: "Not Found"

  - `status` (integer, required)
    Enum: "404"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "customer_not_found"

## Response 409:

  - `409` (unknown)
    Conflict

## Response 409 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/conflict"

  - `title` (string, required)
    Enum: "Conflict"

  - `status` (integer, required)
    Enum: "409"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "email_already_exists"

## Response 422:

  - `422` (unknown)
    Validation failed

## Response 422 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/validation-failed"

  - `title` (string, required)
    Enum: "Validation Failed"

  - `status` (integer, required)
    Enum: "422"

  - `detail` (string, required)

  - `code` (string, required)
    Enum: "invalid_requirement", "invalid_file_format"

## Response 429:

  - `429` (unknown)
    Rate limit exceeded

## Response 429 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/rate-limit-exceeded"

  - `title` (string, required)
    Enum: "Rate Limit Exceeded"

  - `status` (integer, required)
    Enum: "429"

  - `detail` (string, required)

## Response 429 headers (application/problem+json):

  - `Retry-After` (integer)
    Seconds until the rate limit resets

## Response 500:

  - `500` (unknown)
    Internal server error

## Response 500 fields (application/problem+json):

  - `type` (string, required)
    Enum: "https://docs.dinie.com/errors/internal"

  - `title` (string, required)
    Enum: "Internal Error"

  - `status` (integer, required)
    Enum: "500"

  - `detail` (string, required)

## Response 400 examples:

  - ``Content-Type` is not `multipart/form-data`` (unknown)

  - ``file` part is missing from the multipart request` (unknown)

  - ``requirement_id`, `evidence_type`, or `attachment_type` field is missing` (unknown)

  - `File exceeds the maximum allowed size` (unknown)

## Response 401 examples:

  - `Authorization header is missing` (unknown)

  - `Bearer token is invalid or malformed` (unknown)

  - `Bearer token has expired` (unknown)

## Response 403 examples:

  - `The credential is not permitted to perform this action` (unknown)

## Response 404 examples:

  - `Customer ID does not exist or does not belong to this partner` (unknown)

## Response 409 examples:

  - `Director email is already set` (unknown)

## Response 422 examples:

  - ``requirement_id`/`evidence_type`/`attachment_type` combination is not a valid KYC requirement for this customer` (unknown)

  - `File format is not supported (expected PDF, JPEG, or PNG)` (unknown)

