Gravv DOCS
Docs Agent Get Started
API Reference Upload document

Upload document

Deprecated

Upload a customer document for KYC or KYB verification. This is the first step of the server-to-server verification flow.

Documents are uploaded as base64-encoded strings along with metadata about the document type, customer information, and document details. The document is validated and stored in preparation for verification.

POST/v1/risk/upload-document

Supported document types

The metadata.idDocType field accepts the following values (lowercase):

  • Individual customers: passport, id_card, drivers_license, selfie, residence_permit, utility_bill, bank_card, vehicle_registration_certificate, other

  • Business customers: registration_certificate, company_doc, formation_document, ownership_document, proof_of_address, proof_of_address_document

Selfie documents must be an image (JPEG or PNG); PDF selfies are rejected.

Document subtypes

The supported document subtypes are as follows (case-sensitive, uppercase):

  • FRONT_SIDE: Front side of document
  • BACK_SIDE: Back side of document (if applicable)

File format

The filename extension and the decoded content MIME type must agree and must be one of: image/jpeg, image/png, application/pdf.

Size limits

The maximum decoded document size is 10 MB. The base64-encoded payload sent in content may be up to roughly 13.3 MB. Larger payloads are rejected at the ingress layer with a 413 before reaching the service.

Idempotency

The Idempotency-Key header is required on this endpoint. Replays of the same key with the same payload return the original response; replays with a different payload return 422.

After uploading all required documents, call the Initiate KYC S2S endpoint to start the verification process.

Headers

Unique key to dedupe retries. Required on this endpoint; 1–255 ASCII printable characters. Missing or malformed keys return 400.

Request Body

ID of the customer this document belongs to

Optional upstream applicant identifier. When omitted (server-to-server flow) the service resolves the applicant from customer_id.

Type of document being uploaded. Individual customer documents include passport, id_card, drivers_license, selfie, residence_permit, utility_bill, bank_card, vehicle_registration_certificate, and other. Business customer documents include registration_certificate, company_doc, formation_document, ownership_document, proof_of_address, and proof_of_address_document.

Possible values: passport, id_card, drivers_license, selfie, residence_permit, utility_bill, bank_card, vehicle_registration_certificate, other, registration_certificate, company_doc, formation_document, ownership_document, proof_of_address, proof_of_address_document

Subtype indicating which side of the document. Must be uppercase; lowercase values are passed through to the upstream verifier and may be silently rejected.

Possible values: FRONT_SIDE, BACK_SIDE

Document issuing country (ISO 3166-1 alpha-3 code, uppercase)

First name as shown on document

Middle name as shown on document (optional)

Last name as shown on document

Document issue date (YYYY-MM-DD)

Document expiration date (YYYY-MM-DD)

Document identification number

Date of birth (YYYY-MM-DD)

Place of birth as shown on document

Base64-encoded document content. The decoded bytes must be a JPEG, PNG, or PDF; the service sniffs the leading bytes and rejects other MIME types. Maximum decoded size is 10 MB.

Original filename of the document. Extension must be one of .jpg, .jpeg, .png, .pdf (case-insensitive); the file extension is validated before the content MIME sniff.

Whether to return document quality warnings in the response

Request Examples

{
"customer_id": "b84d9a52-2978-43e5-9b86-eac9839e1146",
"metadata": {
"idDocType": "passport",
"idDocSubType": "FRONT_SIDE",
"country": "USA",
"firstName": "John",
"middleName": "Michael",
"lastName": "Doe",
"issuedDate": "2020-01-15",
"validUntil": "2030-01-15",
"number": "A12345678",
"dob": "1990-05-20",
"placeOfBirth": "New York, NY"
},
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"filename": "passport_front.jpg",
"return_doc_warnings": true
}
{
"customer_id": "b84d9a52-2978-43e5-9b86-eac9839e1146",
"metadata": {
"idDocType": "selfie",
"idDocSubType": "FRONT_SIDE",
"country": "NGA",
"firstName": "John",
"lastName": "Doe",
"dob": "1990-05-20"
},
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"filename": "selfie.jpg",
"return_doc_warnings": false
}
{
"customer_id": "c84d9a52-2978-43e5-9b86-eac9839e1147",
"metadata": {
"idDocType": "registration_certificate",
"idDocSubType": "FRONT_SIDE",
"country": "NGA",
"firstName": "Acme",
"lastName": "Corporation",
"number": "RC123456",
"issuedDate": "2020-01-15"
},
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"filename": "registration_certificate.pdf",
"return_doc_warnings": true
}
{
"customer_id": "b84d9a52-2978-43e5-9b86-eac9839e1146",
"metadata": {
"idDocType": "id_card",
"idDocSubType": "FRONT_SIDE",
"country": "NGA",
"firstName": "Jane",
"lastName": "Smith",
"number": "ID987654321",
"issuedDate": "2019-06-10",
"validUntil": "2029-06-10",
"dob": "1992-03-15",
"placeOfBirth": "Lagos"
},
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"filename": "id_card_front.jpg",
"return_doc_warnings": true
}

Responses

Status Description
200 Document uploaded successfully
400 Invalid request
404 Customer not found
409 Concurrent in-flight request with the same Idempotency-Key
413 Payload too large. The decoded document exceeds the 10 MB service limit, or the request body exceeded the ingress 15 MB limit. The ingress-layer 413 is returned as HTML by nginx and does not match the schema below.
422 Idempotency-Key reused with a different request payload

200 response

Always "success" on a successful upload

Possible values: success

ID of the customer the document was saved for

Normalised document type derived from metadata.idDocType

Document sub-type as supplied in metadata.idDocSubType

ISO 3166-1 alpha-3 country code as supplied in metadata.country

Human-readable confirmation message

Error information if the request failed

{
"data": {
"status": "success",
"customer_id": "b84d9a52-2978-43e5-9b86-eac9839e1146",
"document_type": "passport",
"document_sub_type": "FRONT_SIDE",
"country": "NGA",
"message": "Document saved. Use /initiate-kyc to submit for verification."
},
"error": null
}
{
"data": {
"status": "success",
"customer_id": "b84d9a52-2978-43e5-9b86-eac9839e1146",
"document_type": "selfie",
"document_sub_type": "FRONT_SIDE",
"country": "NGA",
"message": "Document saved. Use /initiate-kyc to submit for verification."
},
"error": null
}

400 response

Always null for error responses

Human-readable error message

{
"data": null,
"error": {
"code": "INVALID_ARGUMENT",
"message": "selfie is not a valid document type for business customers",
"details": {}
}
}
{
"data": null,
"error": {
"code": "INVALID_ARGUMENT",
"message": "filename is required",
"details": {}
}
}
{
"data": null,
"error": {
"code": "INVALID_ARGUMENT",
"message": "Invalid base64 encoded content",
"details": {}
}
}
{
"data": null,
"error": {
"code": "INVALID_ARGUMENT",
"message": "missing idempotency key in request headers",
"details": {}
}
}
{
"data": null,
"error": {
"code": "INVALID_ARGUMENT",
"message": "unsupported file content type: application/octet-stream. Supported types: JPEG, PNG, PDF",
"details": {}
}
}

404 response

Always null for error responses

Human-readable error message

{
"data": null,
"error": {
"code": "NOT_FOUND",
"message": "Customer not found",
"details": {}
}
}

409 response

Always null for error responses

Human-readable error message

{
"data": null,
"error": {
"code": "CONFLICT",
"message": "A request with the same Idempotency-Key is currently being processed",
"details": {}
}
}

413 response

Always null for error responses

Human-readable error message

{
"data": null,
"error": {
"code": "PAYLOAD_TOO_LARGE",
"message": "file too large: content exceeds maximum allowed size of 10MB",
"details": {}
}
}

422 response

Always null for error responses

Human-readable error message

{
"data": null,
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "Idempotency-Key was previously used with a different request payload",
"details": {}
}
}

Authorization

  • ApiKeyAuth
Was this page helpful?
Assistant
Responses are generated using AI and may contain mistakes.

Ask me anything about the documentation.

ESC