Skip to main content

Presign a Document Upload

Authorizes the upload of one identity document and returns a form to post the file to. The file goes straight to storage, never through this API.

An individual's record has three slots: face (a selfie), document-front and document-back. Request Verification needs face and document-front; document-back is for documents that have one. Presigning a slot that already holds a document replaces it, under the same document_id.

Takes a workspace-scoped API key or a dashboard session. An account-scoped key is refused with 401.

New in v3: v2 took documents through its verification link.

Authorization:

Every request is signed with your API key: a short-lived JWT, signed with your private key, sent in one header on /v3/* and /api/v2/* alike.

Headers:
Authorization: APIKey {SIGNED_JWT}

How to build and sign the JWT: Authentication.

Endpoint

POST

/v3/customers/{customer_id}/kyc/documents/presign

Path parameters​

ParameterTypeDescription
customer_idstring (cst_…)Required. The customer. Its record must be open and pending or needs_update.

Request Body Sample​

{
"slot": "document-front",
"content_type": "image/png",
"size_bytes": 524288,
"file_name": "passport-front.png"
}

Request Body Schema​

FieldTypeDescription
slotstringRequired. face, document-front or document-back.
content_typestringRequired. application/pdf, image/jpeg or image/png. The file you upload must have exactly this type.
size_bytesintegerRequired. The file's size in bytes, greater than zero and within the per-file limit. It reserves room in the record's budget; the real size is read from storage when you complete the upload.
file_namestringOptional. The file's name, kept for display only.

All of a record's documents together share one budget, because the provider receives them in a single request. A file within the per-file limit can still be refused when it does not fit next to the others. List Documents returns both limits (currently 3 MiB per file and 7 MiB in all).

Response Sample​

{
"document_id": "doc_01k8x4q660fmpa2fzyf5wwq7m6",
"url": "https://uploads.example.com/kyc-documents",
"fields": {
"key": "kyc/019a3a44-93e0-709d-965e-da32dae44550/019a3a4b-98c0-7d2c-a13f-fe7979cb9e86.png",
"Content-Type": "image/png",
"policy": "eyJleHBpcmF0aW9uIjoiMjAyNS0xMC0zMVQxMjo1ODo0NFoiLCJjb25kaXRpb25zIjpbXX0=",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "ASIAEXAMPLEKEYID/20251031/us-east-1/s3/aws4_request",
"X-Amz-Date": "20251031T124344Z",
"X-Amz-Security-Token": "IQoJb3JpZ2luX2VjEXAMPLE...",
"X-Amz-Signature": "5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924aEXAMPLE"
},
"remaining_bytes": 6815744
}

The url and fields above are illustrative: use exactly what you receive.

Response Schema​

FieldTypeDescription
document_idstring (doc_…)The document. Use it to complete or delete it.
urlstringWhere to post the file.
fieldsobjectForm fields to send with the file, verbatim. They carry the upload policy and its signature.
remaining_bytesintegerWhat is left of the record's budget after this document.

Uploading the file​

Post a multipart/form-data request to url: every entry of fields first, unchanged, then the file in a part named file, last. Anything after the file part is ignored.

curl -X POST "$URL" \
-F "key=$KEY" -F "Content-Type=image/png" -F "policy=$POLICY" \
-F "X-Amz-Algorithm=$ALGORITHM" -F "X-Amz-Credential=$CREDENTIAL" \
-F "X-Amz-Date=$DATE" -F "X-Amz-Security-Token=$TOKEN" -F "X-Amz-Signature=$SIGNATURE" \
-F "file=@passport-front.png"

Storage itself refuses an empty file, one over the per-file limit, or one of another type than content_type. The upload URL expires after a short time (15 minutes): presign again if it lapses. Then call Complete a Document Upload.

Errors​

StatusmessageWhen
400unsupported_document_content_typecontent_type is not PDF, JPEG or PNG.
400document_too_largesize_bytes is negative or exceeds the per-file limit.
400failed to parse requestThe body is not valid JSON, slot is not one of its values, or customer_id is not a cst_… TypeID.
401unauthorizedMissing or invalid signature, or the caller is an account-scoped key or a customer session.
403forbiddenA dashboard member whose role does not allow this. A workspace-scoped key always may.
404kyc_not_foundThe customer has no record: open one first.
409document_budget_exceededThe file does not fit in what is left of the record's budget. Delete or replace a document first.
409kyc_verification_in_flightThe record is in_review.
409kyc_already_approvedThe record is approved.
409kyc_rejectedThe record is rejected.
422Validation failedslot, content_type or size_bytes is missing, or size_bytes is 0; details names it.

Support and Resources​

If you need assistance or have any questions, our support team is here to help. You can contact our support team at support@blockwyre.com.

Stay Updated​

Stay up-to-date with the latest news, updates, and features from BlockWyre by following us on social media:

We are excited to have you on board and look forward to seeing how you leverage BlockWyre's powerful tools to enhance your financial operations. Happy integrating!