KYC submission
After creating a customer, you need to upload KYC documents + submit them for review with our regulated KYC partner. The flow:
- Request a pre-signed upload URL for each file you need to attach (
POST /v1/customers/{id}/files). - PUT the file bytes directly to the returned URL.
- Attach the uploaded files to the customer with named slots (
POST /v1/customers/{id}/files/attach). - Submit KYC (
POST /v1/customers/{id}/kyc) — triggers verification review. - Wait for the
customer_verifiedwebhook OR pollGET /v1/customers/{id}until status flips.
Step 1 — Request upload URL
POST /v1/customers/{id}/files
Request
{
"file_category": "id_document",
"filename": "passport.jpg",
"content_type": "image/jpeg"
}| Field | Notes |
|---|---|
file_category | One of: id_document, id_document_back, proof_of_address, liveness_check |
filename | Original filename (preserved upstream) |
content_type | MIME — image/jpeg, image/png, application/pdf |
Response
{
"object": "file_upload_intent",
"file_id": "file_xxx",
"upload_url": "https://upload-storage.example.com/...",
"expires_at": "2026-05-05T12:39:56Z",
"required_headers": {
"Content-Type": "image/jpeg"
}
}The upload_url is a pre-signed PUT URL valid for ~5 minutes. PUT the file bytes directly with the indicated Content-Type header.
Step 2 — Upload the file
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @passport.jpgThe endpoint returns 200 on success. On expiry / wrong content-type, it returns 4xx — request a fresh URL.
Step 3 — Attach files to customer
POST /v1/customers/{id}/files/attach
After ALL files are uploaded, attach them to the customer in named slots:
{
"id_file": "file_xxx",
"id_file_back": "file_yyy",
"proof_of_address_file": "file_zzz"
}id_file is mandatory — without it the verification flow won’t trigger. Other slots are optional depending on the customer’s country.
Response
200 OK with a confirmation envelope.
Step 4 — Submit KYC
POST /v1/customers/{id}/kyc
Submits the full KYC package to our regulated KYC partner for review. After this, the customer is locked into the verification pipeline; you can’t re-upload documents until they’re either verified or rejected.
{}(Empty body — all data was captured at customer-create + file-attach.)
Response
{
"object": "customer",
"id": "ckcust_xxx",
"status": "pending",
"kyc_submitted_at": "2026-05-05T12:34:56Z",
...
}The customer’s status stays pending until verification completes. Typical review window: a few hours to 1 business day.
Step 5 — Listen for verification webhook
Subscribe your webhook endpoint to customer_verified and customer_rejected events:
{
"event": "customer_verified",
"data": {
"object": "customer",
"id": "ckcust_xxx",
"customer_reference": "pouch-user-12345",
"status": "verified",
"verified_at": "2026-05-05T18:23:11Z"
}
}{
"event": "customer_rejected",
"data": {
"object": "customer",
"id": "ckcust_xxx",
"customer_reference": "pouch-user-12345",
"status": "rejected",
"rejected_at": "2026-05-05T18:23:11Z",
"rejection_reason": "ID document unreadable"
}
}On rejection, you’ll need to create a fresh customer with a NEW customer_reference + re-upload corrected documents. The upstream rail doesn’t allow re-submitting on a rejected customer record.
Recovery: customer rejected
If a customer is rejected:
- Notify your end-user (e.g. “Your verification couldn’t be completed — please retry with a clearer photo of your ID.”)
- On retry, generate a NEW
customer_reference(e.g. append-r2to the original) — the upstream rail won’t accept a re-submission on the original ref. - Repeat steps 1-5 with the new customer record.
The old (rejected) customer record stays in our DB for audit but is excluded from active operations.
Best practices
- Validate file size + format client-side before requesting an upload URL — saves a round-trip if the file is bad.
- Capture user-facing errors on the upload PUT — a 403 there typically means the URL expired; request a fresh one.
- Don’t submit KYC until ALL required files are uploaded — partial submissions get rejected.
- Monitor verification time — if a customer’s
pendingstatus persists > 24 hours, contact Technest support to investigate at the upstream rail. - Capture rejection reasons in your UI — don’t surface raw upstream codes to your end-users; map them to friendly messages.