---
title: "Upload a customer supporting document"
method: POST
path: "/customers/{customer_id}/documents"
tags: ["Customers"]
---

# Upload a customer supporting document

`POST /customers/{customer_id}/documents`

## Request

- Base URL: `https://app-sandbox.resolvepay.com/api`
- URL: `https://app-sandbox.resolvepay.com/api/customers/{customer_id}/documents`
- Auth: one of:
  - HTTP bearer
  - HTTP basic
- TypeScript: <https://skmtc.dev/resolvepay/apis/resolve-api-reference/docs/customers/:customer_id/documents/post.ts> (a function with typed inputs; its response is checked against the schema)

Attaches a supporting document to a customer and starts its transfer into Resolve's document
validation service. Use this to hand Resolve buyer data you already hold — bank statements,
financial statements, credit references, or payment history — so it can be used in a credit decision.

Create the customer first; this endpoint is separate from customer creation and belongs to the
merchant v5 API. MCP clients use `create_customer_document` with the returned customer ID as
`merchant_customer_id`. In ChatGPT, attach the file as `download_url` and supply `filename` and
`filetype` separately. See the <a href="/guides/mcp-tools">Merchant MCP tool reference</a>.

The transfer mode is determined by the request shape:
- Omit `download_url` and Resolve returns a presigned S3 `upload_url` (`transfer_method=presigned_upload`).
  PUT the document bytes to that URL with the headers in `upload_headers` before `upload_expires_at`.
- Supply `download_url` and Resolve queues a background download job (`transfer_method=download_url`).
  There is nothing to upload.

Documents are validated asynchronously, so a successful response means the document was accepted for
transfer, not that it passed validation. Poll <a href="#operation/fetchCustomer">#fetchCustomer</a> for
the resulting `credit_status` and limit changes; these are not per-document validation status.

**Fulfilling a banking-data request.** When a credit decision is waiting on bank statements, pass the
open request's ID as `additional_data_request_id` alongside a `bank_statements` upload. Resolve fulfills
that request once the document validates. The field is only accepted with `document_type`
`bank_statements`, and is rejected with `422` if it does not identify a banking-data request on this
customer that is still awaiting a response.

Validation notes:
- `bank_statements` must be PDFs; other document types also accept PNG, JPEG, CSV, XLS, and XLSX
- `filename` must include an extension matching `filetype`
- `download_url`, when provided, must use `http` or `https`, carry no embedded credentials, and resolve
  to a public host

For remote downloads, queue dispatch runs after the document row is committed. A dispatch failure at
that point does not roll the document back — the response is still successful and
`queue_dispatch_status` comes back as `failed`.

## Path parameters

- `customer_id` string, required

## Request body

- union
  - CustomerBankStatementPresignedRequest: Requests a presigned upload URL for a PDF bank statement. Omit `download_url` and PUT the document bytes to the `upload_url` returned in the response.
    - `document_type` 'bank_statements', required: The type of supporting document being uploaded.
    - `additional_data_request_id` string: Optional open banking-data additional data request to fulfill. Must reference an additional data request on this customer with `request_type` `banking_data` that is still awaiting a response — anything else is rejected with `422`. This field is only accepted when `document_type` is `bank_statements`.
    - `filename` string, required: Filename including a `.pdf` extension.
    - `filetype` 'application/pdf', required: Bank statements must be uploaded as PDFs.
  - CustomerDocumentPresignedRequest: Requests a presigned upload URL for a supporting document. Omit `download_url` and PUT the document bytes to the `upload_url` returned in the response.
    - `document_type` 'credit_references' | 'financial_statements' | 'payment_history' | 'other', required: The type of supporting document being uploaded.
    - `filename` string, required: Filename including an extension compatible with `filetype`. The extension must match the MIME type — `.pdf`, `.png`, `.jpg`/`.jpeg`, `.csv`, `.xls`, or `.xlsx`.
    - `filetype` 'application/pdf' | 'image/png' | 'image/jpeg' | 'image/jpg' | 'text/csv' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', required: MIME type of the document. The filename extension must match this value.
  - CustomerBankStatementRemoteRequest: Requests an asynchronous download of a PDF bank statement from a URL you host. Resolve fetches the document in the background rather than returning a presigned upload URL.
    - `document_type` 'bank_statements', required: The type of supporting document being uploaded.
    - `additional_data_request_id` string: Optional open banking-data additional data request to fulfill. Must reference an additional data request on this customer with `request_type` `banking_data` that is still awaiting a response — anything else is rejected with `422`. This field is only accepted when `document_type` is `bank_statements`.
    - `filename` string, required: Filename including a `.pdf` extension.
    - `filetype` 'application/pdf', required: Bank statements must be uploaded as PDFs.
    - `download_url` string, uri, required: Public HTTP(S) URL without embedded credentials that Resolve will fetch asynchronously. Local, private, and unresolvable hosts are rejected.
  - CustomerDocumentRemoteRequest: Requests an asynchronous download of a supporting document from a URL you host. Resolve fetches the document in the background rather than returning a presigned upload URL.
    - `document_type` 'credit_references' | 'financial_statements' | 'payment_history' | 'other', required: The type of supporting document being uploaded.
    - `filename` string, required: Filename including an extension compatible with `filetype`. The extension must match the MIME type — `.pdf`, `.png`, `.jpg`/`.jpeg`, `.csv`, `.xls`, or `.xlsx`.
    - `filetype` 'application/pdf' | 'image/png' | 'image/jpeg' | 'image/jpg' | 'text/csv' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', required: MIME type of the document. The filename extension must match this value.
    - `download_url` string, uri, required: Public HTTP(S) URL without embedded credentials that Resolve will fetch asynchronously. Local, private, and unresolvable hosts are rejected.

## Response `200`

Upload instructions for the customer document. The shape depends on the transfer mode requested.

- union
  - CustomerDocumentPresignedResponse: Returned when the request omits `download_url`. Upload the document by issuing a PUT to `upload_url` with the headers in `upload_headers` before `upload_expires_at`.
    - `id` string, required: Unique identifier of the customer document.
    - `document_id` string, required: Alias of the customer document identifier.
    - `document_type` 'bank_statements' | 'credit_references' | 'financial_statements' | 'payment_history' | 'other', required
    - `upload_url` string, uri, required: Presigned S3 URL to PUT the document bytes to.
    - `upload_expires_at` string, date-time, required: Expiration timestamp for `upload_url`.
    - `object_key` string, required: S3 object key where the document is expected to be stored.
    - `transfer_method` 'presigned_upload', required: How the document is moved into Resolve-managed storage.
    - `queue_dispatch_status` 'null', nullable, required: Always `null` for presigned uploads. Only remote-URL requests dispatch a download job.
    - `upload_headers` object, required: Headers to include on the presigned upload PUT request. Always includes: - `x-amz-meta-validation_profile` May include callback routing headers when configured by Resolve: - `x-amz-meta-callback_domain` - `x-amz-meta-callback_url`
    - `validation_profile` 'merchant_underwriting_document_default', required: Validation profile Resolve applies to the document. Managed by Resolve and not overridable.
  - CustomerDocumentRemoteResponse: Returned when the request supplies `download_url`. There is nothing to upload — Resolve fetches the document asynchronously.
    - `id` string, required: Unique identifier of the customer document.
    - `document_id` string, required: Alias of the customer document identifier.
    - `document_type` 'bank_statements' | 'credit_references' | 'financial_statements' | 'payment_history' | 'other', required
    - `upload_url` string, nullable, required: Always `null` for remote downloads.
    - `upload_expires_at` string, date-time, nullable, required: Always `null` for remote downloads.
    - `object_key` string, required: S3 object key where the fetched document will be stored.
    - `transfer_method` 'download_url', required: How the document is moved into Resolve-managed storage.
    - `queue_dispatch_status` 'queued' | 'failed', required: Result of dispatching the background download job. Dispatch happens after the document row is committed, so a `failed` dispatch still returns `200` — the document is marked failed rather than the request being rejected. Retry by submitting the request again.
    - `upload_headers` object, required: Empty for remote downloads, since there is no presigned PUT to sign headers for.
    - `validation_profile` 'merchant_underwriting_document_default', required: Validation profile Resolve applies to the document. Managed by Resolve and not overridable.

## Other responses

- `400`: Bad request error
- `401`: Unauthorized error
- `404`: Not found error
- `422`: `additional_data_request_id` is not an open banking-data request for this customer
- `429`: Rate limit error

---

[API](https://skmtc.dev/resolvepay/apis/resolve-api-reference.md) - [All operations](https://skmtc.dev/resolvepay/apis/resolve-api-reference/llms.txt) - [OpenAPI document](https://skmtc.dev/resolvepay/apis/resolve-api-reference/revisions/c62edc454aaa?raw)
