Start a supporting-document upload for a customer
Declares a KYC/KYB document and returns a short-lived upload_url the client PUTs the file bytes to. Documents may belong to the customer itself or to one of its associated persons. Use generic document categories such as company_registration, identity_document, selfie, liveness, proof_of_address, ownership_structure, financial_statement, and source_of_funds.
Request
- Base URLhttps://developers.ozav.io/v2
- Auth
- API key in header X-API-Key
- or HTTP bearer
Request body
Who this document belongs to. Omit for customer-scoped documents.
Required when subject_type is associated_person. Opaque ozav_ap_... id.
The kind of KYC/KYB document. Jurisdiction-agnostic - generic categories, never country-specific artifact names - because this API onboards your customers worldwide.
What this list is, and what it is not. It is the vocabulary for declaring what you are uploading. It is not a per-country list of which artifact satisfies which category: whether a given national ID, driving licence or utility bill is accepted for a specific customer is decided in review, not by this enum, and OZAV does not publish a per-jurisdiction acceptance table. Declare the category that best describes the artifact and upload it; if something is missing or unusable you get a named outcome on the verification, not a silent rejection.
The fields a customer must supply are a separate question, answered by requirements.missing_fields on the customer itself. That set is driven by the country on tax_id / registration, and it does not vary by the currency of any account you later open.
Required versus optional, and why nothing here blocks. For an international account the receiving institution asks for a defined set of company information. Some categories below satisfy part of that set and some do not apply to every company - a Brazilian company, for example, has no separate memorandum of association, because its Contrato Social is both the constitutive act and the articles.
So this API accepts every category at any time and refuses none of them for being absent. Upload what the company has, under the category that describes it.
What this API does not do yet, said plainly. requirements on GET /customers/{id} reports missing onboarding fields, not missing documents - it will not tell you which of the categories above are still outstanding. Document review happens at the receiving institution, and today its outcome reaches you through your account contact, not through this API. Publishing the list here without saying that would suggest a completeness signal that does not exist.
A company that cannot produce one of these is not blocked from being created. It is blocked, later and visibly, from having an account opened - and the difference matters: the first is a wall at the door, the second is a list you can work through.
Three categories for the Brazilian named account. tax_registration is the company's tax registration certificate (in Brazil, the Cartão CNPJ). pep_declaration is a politically-exposed-person declaration, one per partner or legal representative (subject_type: associated_person), optional except for a BRL account. income_tax_return is the company's income tax return, accepted as evidence of economic capacity alongside financial_statement. A bank statement is not accepted as economic capacity by the Brazilian receiving institution; send a balance sheet or the tax return instead.
Free-text label describing what this file is, in your own words. Strongly recommended whenever doc_type is other, because without it the document is indistinguishable from any other other in review. It complements doc_type and never replaces it: the type is what drives requirements, the label is what a human reads.
Document side when applicable. For doc_type: identity_document the side decides which requirement the file closes: front (or omitted) closes the front, back closes the back (government_id_back in documents_due), and single - front and back in one image - closes both. Omitting side keeps closing only the front, so to satisfy an open back requirement send the back with side: back.
ISO 3166-1 alpha-2 issuing country when applicable.
MIME type of the file to upload (e.g. application/pdf, image/png). Optional integrity hint.
Declared file size in bytes. Optional integrity hint.
Lowercase hex SHA-256 of the file. Optional integrity hint; rejected if malformed.
Example request
{
"label": "Articles of Association (2025 amendment)",
"mime": "application/pdf"
}Response
Upload grant created; PUT the file bytes to upload_url.
Opaque document id.
Resource type discriminator; always the literal document.
The customer this document belongs to.
Whose document this is. customer - the customer itself. associated_person - one of a business customer's associated persons, named in associated_person_id.
Present when subject_type is associated_person.
The kind of KYC/KYB document. Jurisdiction-agnostic - generic categories, never country-specific artifact names - because this API onboards your customers worldwide.
What this list is, and what it is not. It is the vocabulary for declaring what you are uploading. It is not a per-country list of which artifact satisfies which category: whether a given national ID, driving licence or utility bill is accepted for a specific customer is decided in review, not by this enum, and OZAV does not publish a per-jurisdiction acceptance table. Declare the category that best describes the artifact and upload it; if something is missing or unusable you get a named outcome on the verification, not a silent rejection.
The fields a customer must supply are a separate question, answered by requirements.missing_fields on the customer itself. That set is driven by the country on tax_id / registration, and it does not vary by the currency of any account you later open.
Required versus optional, and why nothing here blocks. For an international account the receiving institution asks for a defined set of company information. Some categories below satisfy part of that set and some do not apply to every company - a Brazilian company, for example, has no separate memorandum of association, because its Contrato Social is both the constitutive act and the articles.
So this API accepts every category at any time and refuses none of them for being absent. Upload what the company has, under the category that describes it.
What this API does not do yet, said plainly. requirements on GET /customers/{id} reports missing onboarding fields, not missing documents - it will not tell you which of the categories above are still outstanding. Document review happens at the receiving institution, and today its outcome reaches you through your account contact, not through this API. Publishing the list here without saying that would suggest a completeness signal that does not exist.
A company that cannot produce one of these is not blocked from being created. It is blocked, later and visibly, from having an account opened - and the difference matters: the first is a wall at the door, the second is a list you can work through.
Three categories for the Brazilian named account. tax_registration is the company's tax registration certificate (in Brazil, the Cartão CNPJ). pep_declaration is a politically-exposed-person declaration, one per partner or legal representative (subject_type: associated_person), optional except for a BRL account. income_tax_return is the company's income tax return, accepted as evidence of economic capacity alongside financial_statement. A bank statement is not accepted as economic capacity by the Brazilian receiving institution; send a balance sheet or the tax return instead.
Which face of a two-sided document these bytes are. single for a document captured in one image. null where the document type has no sides (a PDF statement).
ISO 3166-1 alpha-2 country that issued the document, when known. null when the document type has no issuer (a proof of address) or it was not supplied.
pending_upload = grant issued, bytes not yet confirmed; received = bytes present; rejected = failed review.
Content type of the stored bytes, as observed on upload. null while status is pending_upload.
Size of the stored bytes. null while status is pending_upload.
SHA-256 of the stored bytes, computed by OZAV on receipt - not a value you send. Compare it against your own digest to prove the upload was not truncated. null while status is pending_upload.
When the upload grant was created (RFC 3339, UTC), not when bytes arrived.
When the record last changed (RFC 3339, UTC) - the receipt of bytes and a review outcome both move it.
Short-lived upload URL - PUT the raw file bytes here. Not returned by the list endpoint.
Send your API key on this PUT as well. The embedded upload_token scopes the grant to this one customer/document pair and expires on its own, but it does not replace authentication - a PUT without X-API-Key (or Authorization: Bearer) is rejected with MISSING_API_KEY.
Because the key is required, this URL is for your server, not your browser: do not hand it to an end user's device, which would mean shipping your secret key with it. Upload the bytes from your backend.
When upload_url expires.
Example response
{
"id": "ozav_doc_01J8Z9K2M3N4P5Q6R7S8T9U0V1"
}Changes
No recorded changes to this operation across all 1 revision of this API.