Uploading captures
How documents, selfies and liveness recordings reach us when you build your own capture UI
If you use the hosted flow, captures are handled for you and you can skip this page. If you build your own capture experience, this is how the bytes get to us.
Captures are uploaded directly from the client to storage using a short-lived, single-purpose URL that your backend requests. The image or video never passes through your own servers, which keeps biometric data out of your logs, your load balancers and your backups.
Request an upload URL
curl https://api.trustwix.com/v1/verifications/vs_2f8a1c9b4e7d/uploads \
-H "Authorization: Bearer TWK_..." \
-H "Content-Type: application/json" \
-d '{
"kind": "document",
"side": "front",
"content_type": "image/jpeg"
}'| Field | Notes |
|---|---|
kind | document, selfie or liveness. |
side | front or back. Only valid when kind is document. |
content_type | The MIME type of what you are about to upload. |
{
"upload_id": "doc_9b71c4e2",
"key": "…",
"upload_url": "https://…",
"expires_in": 900
}Upload the bytes
PUT the file to upload_url with the same Content-Type you declared. Send no authorization
header, the URL carries its own. A mismatched content type is rejected by storage.
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "image/jpeg" },
body: fileBlob,
});Confirm the upload
Storage does not tell us when you are done, so tell us yourself. This is what moves the capture into the pipeline.
curl https://api.trustwix.com/v1/verifications/vs_2f8a1c9b4e7d/uploads/doc_9b71c4e2/complete \
-X POST \
-H "Authorization: Bearer TWK_..."An unconfirmed upload is invisible
If you skip the confirm call, the capture is never picked up and the verification sits waiting until it expires. Confirm every upload, including retries.
Camera permissions
An embedded capture surface running in an iframe needs the host page to allow it. Serve a
Permissions-Policy header that allow-lists camera and, for liveness, microphone for the
embedding origin. Without it, capture fails silently in most browsers, with no error you can catch.
Practical limits
Send the highest-quality still the device will give you rather than an aggressively compressed one. Most document rejections for readability come from over-compressed uploads, not from bad documents. Upload URLs are short-lived, so request one at the moment you are ready to send, not at the start of the session.