Partners
Markdown

Upload a document

POST /api/v1/partner/customers/{customerId}/documents

Required scope: documents:write. No Idempotency-Key.

Contributes one piece of KYB evidence for your customer. This is the endpoint that carries Flow A from “the business fields are filled in” to “the case can be reviewed”: a verification is only submitted once the required documents exist.

multipart/form-data, not base64 JSON

The body is multipart/form-data. Evidence is routinely a 15 MB scan, and base64 inflates it by a third before it reaches a body parser.

curl -X POST https://www.niftipay.com/api/v1/partner/customers/pc-1/documents \
  -H "Authorization: Bearer <partner_api_key>" \
  -F "document_type=certificate_of_incorporation" \
  -F "file=@/path/to/incorporation.pdf;type=application/pdf"
Part Required Notes
document_type yes One of the five types below.
file yes The bytes. 1 byte to 15 MB.
file_name no Overrides the uploaded part’s filename. Basename only — directory segments are stripped.

document_type — certificate_of_incorporation · proof_of_address · director_id · bank_statement · processing_statement · other

other is for evidence with no name of its own — a shareholder register, a licence, a bank letter — usually in response to a requirement that asked for one. It is accepted on upload and is not required at submit, so uploading one never changes what completeness means.

Content type must be application/pdf, image/jpeg or image/png. Anything else is 415.

Uploading twice is safe

Uploads append; they do not replace. Multiple documents of the same type are allowed and submission takes the latest of each. That is also why the endpoint needs no Idempotency-Key — a retried upload leaves the newest row winning, which is the same outcome as the one that did not need retrying.

To replace a rejected document, upload a new one of the same type. There is no delete.

Response 201

{
  "request_id": "req-1",
  "api_version": "2026-08-01",
  "data": {
    "document": {
      "document_id": "ba189d7e-702d-4139-9a46-8c0a8e8a1c00",
      "document_type": "certificate_of_incorporation",
      "file_name": "incorporation.pdf",
      "mime_type": "application/pdf",
      "file_size_bytes": 459,
      "status": "uploaded",
      "rejection_reason": null,
      "submitted_by_partner_id": "client-1",
      "uploaded_at": "2026-08-27T09:44:52.433Z"
    }
  }
}

Order of operations

A verification must exist before evidence can attach to it. Uploading to a customer whose case has never been started is 404, with a message that says so — call Create a verification first, even with only partial business fields.

Once the case is under review the endpoint is 409: evidence cannot change underneath a reviewer. Either wait for the outcome and upload again if something was rejected, or — when you are holding a document nobody has asked for yet, say an identity document for a second UBO — raise a requirement for it first. An open requirement reopens the case for exactly what it names, so the upload is then accepted without the whole application being resubmitted.

Errors

Status code Meaning
400 invalid_request Body was not multipart/form-data.
403 insufficient_scope Token was not minted with documents:write.
404 resource_not_found Customer is not yours, or no verification has been started yet.
409 verification_in_progress The case is under review. Raise a requirement to reopen it for this document.
413 invalid_request Empty file, or larger than 15 MB.
415 unsupported_media_type Content type is not PDF, JPEG or PNG.
422 invalid_request Unknown document_type, or no file part.