Customers
Individuals and businesses, and how the customer object doubles as the verification intake.
One object, two kinds
A customer is your end user. kind is required, and there is no
default: a silently defaulted individual for a forgotten field is the wrong
record to fail into.
{
"kind": "individual",
"first_name": "Ana",
"last_name": "Silva",
"email": "ana@example.com",
"phone": "+14155550123",
"date_of_birth": "1993-04-12",
"nationality": "US",
"residence_country": "US",
"address": {
"street_line_1": "300 Post St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94108",
"country": "US"
},
"id_document": {"kind": "passport", "number": "P123456"},
"tax_id": "078-05-1120",
"tax_residence_country": "US",
"tos_acceptance": {"ip_address": "203.0.113.7"},
"partner_reference_id": "user-8213"
}
Only a terms path is strictly required. Names are not, so that a
partially known person can exist as a legal record before they can
transact. middle_name is accepted beside the other two.
Most of this can come from the images instead. At submit we read the identity document, the proof of address, and a proof of tax identification if you send one, then fill only the fields you left empty: the names, date of birth, nationality, the identity document's kind and number, the address, and the tax data. A value you send is never overwritten. Anything the documents cannot supply surfaces in a requirement bucket. See Documents are read at submit.
{
"kind": "business",
"legal_name": "Kunde Inc",
"trade_name": "Kunde",
"business_description": "Wholesale coffee importer",
"business_kind": "corporation",
"registration_number": "DE-12345",
"incorporation_date": "2019-03-01",
"vat_number": "US812345678",
"website": "https://kunde.example",
"controllers": [
{
"first_name": "Max",
"last_name": "Muster",
"date_of_birth": "1981-07-02",
"has_ownership": true,
"ownership_percentage": 60,
"has_control": true,
"is_signer": true,
"role": "ceo",
"id_document": {"kind": "passport", "number": "C9876"}
},
{
"first_name": "Erika",
"last_name": "Muster",
"is_director": true
}
],
"tos_acceptance": {"ip_address": "203.0.113.9"}
}
Only a terms path is required. legal_name is optional, and so is
every other company and person field shown here.
The documents a business owes depend on its legal form, so send
business_kind when you know it: the endorsement's missing bucket
then lists every document from the start. See
Documents we ask for.
A business is read from its documents the same way an individual is.
At submit we read the registration document for the legal name, legal
form, registration number, incorporation date, and registered address.
The business's own proof of address gives its operating address
(physical_address), and a proof of tax identification gives its
tax_id. Each controller's documents fill that person's names, date
of birth, nationality, identity document number, residential address,
and tax data. A value you send is never overwritten, and what the
documents cannot supply is listed in the endorsement's missing bucket
(see Requirement codes).
Each controller carries its own identifying_information and
documents (purpose proof_of_address or
proof_of_tax_identification), which we hold under that person. A
controller's first_name and last_name are optional too, since the
identity document carries them. trade_name, the name the business
trades under when that differs from its legal name, and
business_description, what it does, are optional.
controllers is one array with role flags, not parallel lists of
owners, directors, and signers. The same person is very often all three,
and parallel arrays force you to send them three times and keep three
copies in sync. Flags are has_ownership (with a required
ownership_percentage), has_control, is_signer, and is_director.
Responses omit the other kind's fields entirely. An individual payload has
no legal_name key at all, rather than a null.
People on a business
Every controller gets an id (ctl_...), and the customer object lists
each one with that id, the names, and the roles:
"controllers": [
{
"id": "ctl_033y2KpQ7vLmN8aRtXwYz1",
"first_name": "Max",
"last_name": "Muster",
"has_ownership": true,
"ownership_percentage": 60.0,
"has_control": true,
"is_signer": true,
"is_director": false,
"role": "ceo"
}
]
A PATCH that sends controllers replaces the whole list. Each person in it
is matched to someone we already hold this way:
- With an
id, it is that person. Their documents stay held under them, so you do not re-send them, and a corrected name keeps them. - Without an
id, it is the person we hold with the same first name, last name, and date of birth, when all three are present. - Otherwise it is a new person, with a new
id.
An id that is not a person on this customer, or the same id twice,
returns 422 invalid_parameter with param: "controllers". A person you
keep also keeps what their documents supplied wherever you send nothing.
Send each id back to keep people stable across updates.
The customer object is the verification intake
Two intake-only arrays ride customer create and PATCH. We hold them for review, never as customer fields.
{
"identifying_information": [
{
"kind": "passport",
"issuing_country": "USA",
"number": "P123456",
"image_front": "<base64>",
"image_back": "<base64, optional>"
}
],
"documents": [
{"purpose": "selfie", "file": "<base64>"},
{"purpose": "proof_of_address", "file": "<base64>"},
{"purpose": "proof_of_tax_identification", "file": "<base64>"}
]
}
identifying_information[].kind:passport,id_card,drivers_license, orresidence_permit. Optional: without it, the kind is read off the image at submit. When it cannot be read, the endorsement asks for it asid_document_kind.identifying_information[].issuing_countryis optional the same way: read off the image, and asked asissuing_countryonly when it cannot be.identifying_information[].numberis optional. Without it, the number is read off the image at submit.- A
kind,issuing_country, ornumberyou send wins over what the image reads. documents[].purpose:selfie,proof_of_address,proof_of_tax_identification(a tax certificate or letter showing the taxpayer identification number),registration_document,articles_of_association(articles of incorporation or organization, bylaws, or a memorandum of association),operating_agreement(an LLC operating agreement, or a partnership or limited-partnership agreement),ownership_information,proof_of_signatory_authority(the list of the people authorized to represent or sign for the business), orother. What a review can ask for per risk or on request also has a purpose:proof_of_source_of_funds(either kind), and for a businessevidence_of_good_standing,directors_registry(a certificate of incumbency),regulatory_license_registration,aml_policy,annual_report,proof_of_tax_exemption, andtrade_name_registration. Which of these a customer owes depends on its kind and, for a business, its legal form. See Documents we ask for.- Images are base64, and
data:URIs are accepted. Up to ten of each per request, and each file at most about 10 MB. A business's controller carries at most 4 identity documents and 4 documents.
Intake is strict. An unknown field on create or update is refused with
422 invalid_parameter naming it, never silently ignored. A file that is
not valid base64 is 422 invalid_parameter too.
Due-diligence fields
A review can ask for the customer's economic profile, the same fields the
industry takes flat on the customer. All are optional at creation and
asked through missing when a review needs them. Send them as codes from
these lists; a value outside the list for the customer's kind returns
422 invalid_parameter.
| Field | Kind | Values |
|---|---|---|
employment_status | individual | employed, self_employed, retired, student, unemployed |
occupation | individual | A lowercase snake_case occupation code, such as software_developer |
source_of_funds[] | individual | company_funds, ecommerce_reseller, gambling_proceeds, gifts, government_benefits, inheritance, investments_loans, pension_retirement, salary, sale_of_assets_real_estate, savings, someone_elses_funds |
source_of_funds[] | business | business_loans, grants, inter_company_funds, investment_proceeds, legal_settlement, owners_capital, pension_retirement, sale_of_assets, sales_of_goods_and_services, third_party_funds, treasury_reserves |
account_purpose[] | individual | charitable_donations, ecommerce_retail_payments, investment_purposes, operating_a_company, other, payments_to_friends_or_family_abroad, personal_or_living_expenses, protect_wealth, purchase_goods_and_services, receive_payment_for_freelancing, receive_salary |
account_purpose[] | business | charitable_donations, ecommerce_retail_payments, investment_purposes, other, payments_to_friends_or_family_abroad, payroll, personal_or_living_expenses, protect_wealth, purchase_goods_and_services, receive_payments_for_goods_and_services, tax_optimization, third_party_money_transmission, treasury_management |
account_purpose_other | business | Free text, required when account_purpose includes other |
expected_monthly_volume_usd | either | under_5k, 5k_to_10k, 10k_to_50k, 50k_to_100k, 100k_to_1m, 1m_to_5m, 5m_to_10m, 10m_to_20m, over_20m |
source_of_funds_description | either | Free text |
source_of_wealth[] | business | affiliate_or_royalty_income, asset_sales, business_dividends_or_profits, charitable_contributions, client_investor_contributions, gambling, inheritance, investments |
source_of_wealth_description | business | Free text |
estimated_annual_revenue_usd | business | 0_99999, 100000_999999, 1000000_9999999, 10000000_49999999, 50000000_249999999, 250000000_plus |
expected_monthly_payments_usd | business | A whole USD amount |
ownership_structure | business | bearer_shares_or_undisclosed_nominee_arrangement, fund, majority_owned_subsidiary_of_fi_or_nbfi, majority_owned_subsidiary_of_publicly_listed_company, owned_by_trust, privately_owned, publicly_listed_company, wholly_owned_subsidiary_of_fi_or_nbfi, wholly_owned_subsidiary_of_publicly_listed_company |
business_industry[] | business | NAICS codes, 2 to 6 digits |
physical_address | business | The operating address, when it differs from the registered one |
is_politically_exposed, is_us_tax_person, is_us_citizen, is_funds_owner | either | Booleans |
Nothing here enters review on its own. We hold documents until the
customer's first submission, POST /api/customers/{customer_id}/verifications.
After it, a PATCH that changes something resubmits by itself. See
Verification & Endorsements.
Requesting endorsements
Enrollment is explicit. A customer is reviewed only for the endorsements you name, and that review is its verification.
{"endorsements": ["endo_usd"]}
Requesting endo_usd needs contact fields no document can supply, already
on the customer or sent in the same request. For an individual that is email and phone. For a
business it is email. Missing ones return
422 endorsement_profile_required naming them, in sandbox as well as live.
You can request endorsements later with a PATCH.
Tax data is not needed to request endo_usd, but the review needs it, so
send tax_id, and tax_residence_country for an individual, on create. In
live, until they arrive, the endorsement lists them in missing and the
first submit returns 422 verification_incomplete naming them.
Reading a customer
{
"id": "cus_033y1FhTOmoW9W2jAuSvQx",
"object": "customer",
"kind": "individual",
"first_name": "Ana",
"middle_name": null,
"last_name": "Silva",
"email": "ana@example.com",
"address": {"state": "CA", "country": "US"},
"status": "active",
"tos": {
"status": "accepted",
"tos_version": "2026-08-01",
"accepted_at": "2026-08-26T09:14:40+00:00"
},
"endorsements": [
{
"name": "endo_usd",
"status": "approved",
"requirements": {
"complete": ["compliance_review", "identity", "proof_of_address", "selfie", "terms_of_service"],
"uploaded": [],
"pending": [],
"missing": [],
"issues": []
}
}
],
"partner_reference_id": "user-8213",
"created_at": "2026-08-26T09:14:40+00:00"
}
endorsementsis the verification reading. One entry per endorsement we offer (endo_usdtoday). One you have not requested readsincompletewithcompliance_reviewinmissing. Itsstatusis the gate, and itsrequirementsbuckets show each item's state as a bare documented code.statusis the account itself:pending,active,rejected, orfrozen(set by Rasto; contact support). See Statuses & Lifecycles.
The payload is deliberately lean. Identity inputs you send (date of birth,
phone, documents, tax data) go to review and are never echoed
back, and the address trims to state and country. A business's
controllers list only each person's id, names, and roles. A business
payload also carries trade_name and business_description. Keep your own
copy: the API reflects readiness, not the dossier.
Updating
PATCH /api/customers/{customer_id} updates identity fields and accepts the same
two document arrays. Supplying what a missing or issues bucket asks for
is an ordinary PATCH. After the customer's first submission, a PATCH that
changes something resubmits by itself, and one that changes nothing does
nothing.
Two PATCH semantics to know:
- Nested objects merge.
{"address": {"state": "NY"}}fixes the state alone. Sending the whole object replaces every line it names, and"address": nullclears it. - Reading never overwrites a value you sent. At submit, the documents fill only the fields left empty, or ones an earlier document filled, for an individual, a business, and each of its controllers. A value you supplied changes only through your own PATCH.
Set partner_reference_id to your own user id at creation. It is unique
per environment within your account, filterable on list endpoints, and the
simplest way to join Rasto records to yours. A collision returns
409 partner_reference_id_exists.