API referenceDocuments

Documents

Certivant documents API reference — multipart upload of passports, government IDs, selfies, and proof-of-address files to a KYC request, fetch signed download URLs, and view supported document types and status values.

Documents are attached to a request, not to an applicant directly. Every upload moves the parent request closer to "ready for submission" — once pendingDocTypes is empty, you can submit the request for processing.

Upload a document

POST /api/v1/kyc/requests/:requestId/documents    Scope: kyc:write

Multipart upload. Pass documentType (and side if applicable) as query parameters, and the file in a file form field.

Query parameters

ParamTypeRequiredNotes
documentTypeenumyesSee list below
sideenumconditionalfront or back. Required for GOVERNMENT_ID

Form body

FieldTypeNotes
filebinaryThe document file. Max 10 MB. MIME types: image/jpeg, image/png, image/webp, application/pdf

Document types

ValueDescriptionTwo-sided?
GOVERNMENT_IDNational ID card, driver's license, residence permitYes
PASSPORTPassport biodata pageNo
SELFIELive photo of the applicant for face match + livenessNo
PROOF_OF_ADDRESSUtility bill, bank statement, government letter (≤ 3 months old)No
CERTIFICATE_OF_INCORPORATIONKYB — proof the company existsNo
COMPANY_OWNERSHIP_STRUCTUREKYB — org chart or shareholder ledgerNo
BANK_STATEMENTAccount statement for source-of-funds checksNo
OTHERAnything not listed — use sparingly; checks won't run on OTHER documentsNo

Always upload the highest-resolution version you have. The OCR and authenticity checks degrade fast below 1024px on the long edge. JPEG at quality 80+ is fine; avoid pre-compressing to "save bandwidth."

Example

# Upload the front of a driver's license
curl -X POST "https://app.certivant.com/api/v1/kyc/requests/req_01J.../documents?documentType=GOVERNMENT_ID&side=front" \
  -H "Authorization: Bearer ck_live_..." \
  -F "file=@/path/to/license-front.jpg"

Response (201)

{
  "id": "doc_01J...",
  "documentType": "GOVERNMENT_ID",
  "side": "front",
  "status": "pending",
  "fileSize": 412938,
  "mimeType": "image/jpeg",
  "requestStatus": "PENDING_UPLOAD",
  "pendingDocTypes": ["GOVERNMENT_ID", "SELFIE"],
  "message": "Document uploaded. Front of GOVERNMENT_ID received; back of GOVERNMENT_ID still required."
}

The response always tells you what's still missing via pendingDocTypes. When that array is empty, your next call should be POST /requests/:id/submit.

Document status values

  • pending — uploaded, not yet processed (only happens before request submission).
  • verified — passed all authenticity checks after the request was submitted.
  • failed — failed an authenticity check. Look at the linked check records on GET /requests/:id for the specific reason.
  • corrupted — file could not be decoded. Re-upload.

Errors

  • 400 BAD_REQUEST:
    • File exceeds 10 MB.
    • Unsupported MIME type.
    • side missing for GOVERNMENT_ID.
    • documentType not allowed by the org's KYC settings.
  • 404 NOT_FOUND — the parent request doesn't exist in this organization.
  • 409 CONFLICT — request is not in PENDING_UPLOAD. You cannot add documents to a request that has already been submitted.

Get a download URL

GET /api/v1/kyc/requests/:requestId/documents/:docId/url    Scope: kyc:read

Documents are stored in private object storage. To view or download one, fetch a short-lived signed URL.

Response

{
  "url": "https://storage.certivant.com/kyc/org_.../req_.../doc_....jpg?X-Amz-Signature=...",
  "expiresIn": 900
}

expiresIn is in seconds — the URL is valid for 15 minutes. Generate a fresh one whenever you need to display a document; do not cache them.

The returned url is a presigned storage URL (S3 / Azure Blob / GCS). It opens directly in a browser tab and renders with no Authorization header:

  • Images (image/jpeg, image/png, image/webp) → <img src="{url}" />
  • PDFs (application/pdf) → <iframe src="{url}" /> or <object data="{url}" type="application/pdf" />

Check each document's mimeType (from GET /requests/:id) to decide which to render.

Signed URLs are unauthenticated by definition — anyone with the URL can view the document until it expires. Never log them, never include them in emails, never expose them client-side without an authorization check on your side.


Download the raw bytes

GET /api/v1/kyc/requests/:requestId/documents/:docId/download    Scope: kyc:read

Streams the document file bytes back directly, with the stored Content-Type (image/jpeg, image/png, image/webp, or application/pdf) and Content-Disposition: inline. No signed URL, no redirect.

curl -L "https://app.certivant.com/api/v1/kyc/requests/req_01J.../documents/doc_01J.../download" \
  -H "Authorization: Bearer ck_live_..." \
  -o government_id_front.jpg

Prefer this over the signed-URL route when you render documents inside your own dashboard:

  • It works for every storage backend, including local disk — whose signed /uploads/… URL is only reachable from inside the Certivant host and will 404 from another origin.
  • Proxy it through your backend and serve it same-origin (<img src="/your-proxy/doc"> for images, <iframe> for PDFs). The Authorization: Bearer key stays server-side and never reaches the browser.
  • No storage URL is ever exposed, so there's nothing to leak or expire.

Which one do I use? Use /url when you're fine sending the browser a short-lived public storage link (cloud storage, e.g. S3/Azure). Use /download when you want to keep everything behind your own auth, or when Certivant is running on local-disk storage. The /download route is the safe default for a partner console.


Replacing documents

You cannot edit a document in place. If the applicant uploaded a blurry photo and you want a retake:

  1. The request must be in PENDING_UPLOAD (or you must resubmit a rejected request first to clear the prior documents).
  2. Upload a new document with the same documentType and side. The previous one is superseded — only the latest version is used for processing.

This rule exists for audit integrity: an immutable history of every upload survives in the audit log, even when the active document changes.


Listing documents on a request

There is no separate documents-list endpoint. The full list is included in the response from GET /api/v1/kyc/requests/:id:

{
  "id": "req_...",
  "documents": [
    { "id": "doc_a", "documentType": "GOVERNMENT_ID", "side": "front", "status": "verified", ... },
    { "id": "doc_b", "documentType": "GOVERNMENT_ID", "side": "back", "status": "verified", ... },
    { "id": "doc_c", "documentType": "SELFIE", "status": "verified", ... }
  ]
}

Iterate over documents and call /download (to proxy the bytes) or /url (for a signed link) on any specific document you want to display.

  • KYC requests — the parent endpoint your documents attach to.
  • Hosted sessions — let Certivant collect documents from the applicant directly.
  • Schemas — full enumeration of documentType, status, and related values.