Upload a Business Document
A business document goes from your client straight to storage, never through the API, in three steps:
- Presign: say what you are about to upload. The answer is a
document_id, aurland a set of formfields. - Upload:
POSTthe file tourlasmultipart/form-data, with every entry offieldsas is, then the file last, as a part namedfile. Storage refuses a file over the size limit, or of a content type other than the one presigned. - Complete: tell the API the upload is done. Only completed documents (
state: ready) count when you request verification, which needs at least one.
No particular document type is required, and each type holds one file. Presigning a type that already has a file replaces it: the answer carries the same document_id, and the document is pending again until you complete the new upload.
Takes a workspace-scoped API key or a dashboard session. An account-scoped key is refused with 401.
Replaces POST /api/v2/kyb/banking-verification/business/upload-document.
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.
1. Presign
Endpoint
/v3/customers/{customer_id}/kyb/documents/presign
Path parameters
| Parameter | Type | Description |
|---|---|---|
customer_id | string (cst_…) | Required. The business customer. Its record must be open. |
Request Body Sample
{
"slot": "certificate_of_incorporation",
"content_type": "application/pdf",
"size_bytes": 524288,
"file_name": "certificate-of-incorporation.pdf"
}
Request Body Schema
| Field | Type | Description |
|---|---|---|
slot | string | Required. The document type: certificate_of_incorporation, articles_of_incorporation, organization_chart, proof_of_address, ein_confirmation, formation, dba or other. |
content_type | string | Required. application/pdf, image/jpeg or image/png. The upload must carry exactly this type. |
size_bytes | integer | Required. The file's size in bytes, at most max_document_bytes (see List Business Documents). The real size is read from storage when you complete. |
file_name | string | The file's name on the uploader's machine, shown back in listings. Display only. |
Response Sample
{
"document_id": "doc_01m24s2q00fqrbpn5wwx8akzr5",
"url": "https://uploads.example.com/kyb-documents",
"fields": {
"key": "kyb/01a088ec-9080-7dfb-83fc-bdcda39a6ef4/01a08991-5c00-7df0-bb54-bce750a9ff05.pdf",
"policy": "eyJleHBpcmF0aW9uIjoiMjAyNi0wOS0wOVQxNDo1MDowMFoi…",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "ASIA…/20260909/us-east-1/s3/aws4_request",
"X-Amz-Date": "20260909T143500Z",
"X-Amz-Security-Token": "IQoJb3JpZ2luX2Vj…",
"X-Amz-Signature": "5b2f0c…",
"Content-Type": "application/pdf"
}
}
Response Schema
| Field | Type | Description |
|---|---|---|
document_id | string (doc_…) | The document. Use it to complete or delete it. |
url | string | Where to POST the upload. |
fields | object | Form fields to send with the upload, verbatim and before the file. They carry the upload policy and its signature: treat them as opaque, and presign again if the policy has expired. |
Uploading
No Authorization header: the signature travels in the fields.
curl -X POST "https://uploads.example.com/kyb-documents" \
-F "key=kyb/01a088ec-9080-7dfb-83fc-bdcda39a6ef4/01a08991-5c00-7df0-bb54-bce750a9ff05.pdf" \
-F "policy=eyJleHBpcmF0aW9uIjoiMjAyNi0wOS0wOVQxNDo1MDowMFoi…" \
-F "X-Amz-Algorithm=AWS4-HMAC-SHA256" \
-F "X-Amz-Credential=ASIA…/20260909/us-east-1/s3/aws4_request" \
-F "X-Amz-Date=20260909T143500Z" \
-F "X-Amz-Security-Token=IQoJb3JpZ2luX2Vj…" \
-F "X-Amz-Signature=5b2f0c…" \
-F "Content-Type=application/pdf" \
-F "file=@certificate-of-incorporation.pdf"
Errors
| Status | message | When |
|---|---|---|
400 | failed to parse request | The body is not valid JSON, slot is not one of the document types, or customer_id is not a cst_… TypeID. |
400 | unsupported_document_content_type | content_type is not PDF, JPEG or PNG. |
400 | document_too_large | size_bytes is over max_document_bytes, or negative. |
401 | unauthorized | Missing or invalid signature, or an account-scoped key or customer session. |
403 | forbidden | A dashboard member whose role does not allow this. A workspace-scoped key always may. |
404 | customer_not_found | No such customer in the workspace. |
404 | kyb_not_found | This customer has no record. Open it first. |
409 | kyb_verification_in_flight | The record is in_review: documents are locked. |
409 | kyb_already_approved | The record is approved. |
409 | kyb_rejected | The record is rejected. |
422 | Validation failed | slot, content_type or size_bytes is missing, or size_bytes is 0; details names it. |
2. Complete
Endpoint
/v3/customers/{customer_id}/kyb/documents/{document_id}/complete
Call it once the upload succeeded. It reads the file's real size and type from storage and marks the document ready.
Path parameters
| Parameter | Type | Description |
|---|---|---|
customer_id | string (cst_…) | Required. The business customer. |
document_id | string (doc_…) | Required. The document_id the presign answered. |
No request body.
Response
204 No Content, with no body.
Errors
| Status | message | When |
|---|---|---|
400 | failed to parse request | customer_id or document_id is not a TypeID of its kind. |
401 | unauthorized | Missing or invalid signature, or an account-scoped key or customer session. |
403 | forbidden | A dashboard member whose role does not allow this. A workspace-scoped key always may. |
404 | customer_not_found | No such customer in the workspace. |
404 | kyb_not_found | This customer has no record. |
404 | document_not_found | No such document on this record. |
409 | document_not_uploaded | Nothing arrived in storage for this document. Upload it, or presign again. |
Coming from v2
v2 (POST /api/v2/kyb/banking-verification/business/upload-document) | v3 |
|---|---|
the file goes through the API in one multipart/form-data call | presign, upload straight to storage, complete |
accountId, documentType (form fields) | customer_id (path), slot (body) |
| any file type | PDF, JPEG or PNG, up to max_document_bytes |
answers message, documentType, size | presign answers document_id, url, fields; complete answers 204 |
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:
- Instagram: BlockWyre Instagram
- Twitter: BlockWyre Twitter
- Facebook: BlockWyre Facebook
- LinkedIn: BlockWyre LinkedIn
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!