Sender
The Sender is the participant who initiates and pays for a transaction. Every sender must pass through KYC (Know Your Customer) screening, and their transaction limits are determined by their compliance level.
Initial Compliance Setup
At the beginning of your integration, the Inyo compliance team works with your organization to define a custom compliance framework tailored to your product and customer profile. This framework determines:
- Compliance levels β tiers that define how much a customer can send within set timeframes (24h, 30d, 180d)
- Validation rules β the required data and documents for each level (e.g., name, SSN, proof of income)
- Risk controls β thresholds that trigger enhanced due diligence
This configuration is unique per tenant and directly impacts how participants are verified and which operations they can perform.
Creating a Sender (v2 β Recommended)
Endpoint: POST /organizations/{tenant}/v2/people
Authentication: Tenant-level (x-api-key)
β οΈ The v1 endpoint
POST /organizations/{tenant}/peopleis deprecated. Use v2 β it takes the same payload and adds document validation and verification integrated into the KYC solution.
The v2 endpoint accepts the same request shape as v1 (see the field tables below), plus one additional per-document field β documents[].stateCode (issuing state/province, max 32 chars) β and applies a stricter, safer pipeline:
- Rule-driven document validation β per country + document type, tenant-configured rules can require extra fields (e.g.,
stateCodefor US driver's licenses) and enforce format regexes. Violations return422 VALIDATION_ERRORwith per-field errors undererrors["documents.{i}.{field}"], and nothing is persisted. - Synchronous KYC number verification β where the rule requires it, the document number is verified against the Inyo360 KYC service during the request. A KYC rejection returns
422with the rejection detail; if the KYC service is unavailable, the request fails closed with502 KYC_UPSTREAM_ERROR(retry it). - Verification verdicts on record β verified documents carry
kyc_verdict/kyc_verified_aton the person's document records. - Same idempotency as v1: if a person with the same
externalIdexists, the existing person is returned with200; a new person returns201.
No fields are technically required to create a person β but to use them as a sender, they must reach at least Compliance Level 1, which typically requires first name, last name, address, and phone number.
curl --request POST \
--url https://{FQDN}/organizations/$TENANT/v2/people \
--header 'Content-Type: application/json' \
--header "x-api-key: $API_KEY" \
--data '{
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"birthDate": "1990-01-15",
"phoneNumber": "+15551234567",
"gender": "Male",
"externalId": "your-internal-id-001",
"address": {
"countryCode": "US",
"stateCode": "CA",
"city": "San Francisco",
"line1": "123 Market St",
"zipcode": "94105"
},
"documents": [
{
"type": "drivers_license",
"document": "D12345678",
"countryCode": "US",
"stateCode": "CA",
"expireDate": "2030-06-30"
}
],
"occupation": "Software Engineer"
}'
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | For Level 1 | First name |
lastName | string | For Level 1 | Last name |
phoneNumber | string | For Level 1 | Phone with country code (e.g., +15551234567) |
email | string | For US persons | Email address |
gender | string | For US persons | Male, Female, or Other |
birthDate | string | For US persons | Format: yyyy-MM-dd |
externalId | string | No | Your internal reference ID |
address | object | For Level 1 | Residential address |
address.countryCode | string | Yes (in address) | ISO 3166-1 alpha-2 |
address.stateCode | string | For US | US state code (e.g., CA) |
address.city | string | Yes (in address) | City name |
address.line1 | string | Yes (in address) | Street address |
address.line2 | string | No | Additional address info |
address.zipcode | string | Yes (in address) | Postal code |
documents | array | For Level 2+ | Identity documents |
documents[].type | string | Yes (in doc) | Document type β see the accepted values below |
documents[].document | string | Yes (in doc) | Document number |
documents[].countryCode | string | Yes (in doc) | Issuing country (ISO 3166-1 alpha-2) |
documents[].stateCode | string | Per rules (v2 only) | Issuing state/province (max 32) β required by rule for some country/type combinations, e.g. US driver's licenses |
documents[].expireDate | string | No | Expiration date (yyyy-MM-dd) |
documents[].issuer | string | No | Issuing authority or state |
occupation | string | For Level 2 | Person's occupation |
employerName | string | No | Employer name |
Accepted Document Types
On the v2 endpoints, documents[].type uses lowercase values, following the same standard as the KYC solution:
| v2 value | v1 value (deprecated) | Description |
|---|---|---|
passport | PASSPORT | Passport |
drivers_license | DRIVER_LICENSE | Driver's license |
dni | DNI | DNI (Spain / Argentina / Peru) |
cc | CC | CC (Colombia cΓ©dula de ciudadanΓa) |
cpf | CPF | CPF (Brazil) |
id | ID | Generic government ID |
consular_id | CONSULAR_ID | Consular ID (matrΓcula consular) |
voter_id | VOTER_ID | Voter ID |
ssn | SSN | US Social Security number |
itin | ITIN | US ITIN (IRS) |
other | OTHER | Other government-issued document |
Note the plural
drivers_licenseβ v2 corrects v1's singularDRIVER_LICENSEto align with the KYC standard. For a smooth migration, v2 also accepts the legacy uppercase v1 values and the singulardriver_license(all matched case-insensitively and normalized), but new integrations should send the lowercase values.
These are declared document numbers β to verify document images, create a KYC verification session.
β The deprecated v1
PATCH /people/{personId}accepts a narrower set fordocuments[].type(PASSPORT,DRIVER_LICENSE,DNI,CC,CPF,ID,SSN,ITIN) and restrictsdocuments[].countryCodetoUS,BR,CO,PE,KE. The v2PATCH /v2/people/{personId}has no such restriction β its document rules mirror v2 create exactly.
Sample Response
{
"id": "48066496-9445-41b7-acbe-85e069a77cb7",
"firstName": "John",
"lastName": "Doe",
"mainAddressId": "9c2ea7e5-51a2-4ea1-83cf-8948754486f8",
"phoneNumber": "+15551234567",
"email": "john.doe@example.com",
"gender": "Male",
"birthDate": "1990-01-15",
"externalId": "your-internal-id-001",
"updatedAt": "2025-01-15T12:00:00",
"documents": [],
"occupation": "Software Engineer",
"documentId": null,
"sourceOfFundsId": null,
"employerName": null,
"employerAddressId": null
}
Save the returned
idβ this is thesenderIdused in all subsequent API calls.
Behavior notes:
- Idempotent on
externalIdβ if a person with the sameexternalIdalready exists in your tenant, create returns the existing person (200) instead of creating a duplicate. - Senders must be 18+ β
birthDateis rejected if the person would be under 18. - Documents are append-only β updating a person's documents inserts new records and retires the old ones, preserving the compliance audit trail.
Updating a Sender (v2 β Recommended)
Endpoint: PATCH /organizations/{tenant}/v2/people/{personId}
Authentication: Tenant-level
β οΈ The v1 endpoint
PATCH /organizations/{tenant}/people/{personId}is deprecated. The v2 update applies the same rule-driven validation and synchronous KYC number verification as v2 create, and its document rules mirror create exactly (v1's update accepted a narrower document set).
Only fields included in the request body are updated; omitted fields remain unchanged. Documents are additive β each update appends new document records while the history stays visible.
curl --request PATCH \
--url https://{FQDN}/organizations/$TENANT/v2/people/$PERSON_ID \
--header 'Content-Type: application/json' \
--header "x-api-key: $API_KEY" \
--data '{
"occupation": "Consultant",
"documents": [
{
"type": "drivers_license",
"document": "D87654321",
"countryCode": "US",
"stateCode": "CA",
"expireDate": "2031-01-31"
}
]
}'
Address Verification
Use the address check endpoint to pre-validate an address before creating or updating a sender. It applies the same country-aware validation rules (including per-country zipcode formats) as the real save endpoints, so a passing check here means the address will be accepted on POST /people.
curl --request GET \
--url "https://{FQDN}/organizations/$TENANT/addresses/check?countryCode=US&stateCode=CA&city=San+Francisco&line1=123+Market+St&zipcode=94105" \
--header "x-api-key: $API_KEY"
Query parameters: line1, city, stateCode, and countryCode are required; zipcode is validated against the destination country's format rules.
| Response Code | Meaning |
|---|---|
200 | Address is valid β the response includes { "valid": true, "normalized": { ... } } |
422 | Validation failed β VALIDATION_ERROR with a per-field breakdown |
Creating Business Senders (KYB)
For B2B use cases, you can create a company as a sender:
Endpoint: POST /organizations/{tenant}/companies
Authentication: Tenant-level
Companies follow a similar compliance level system but with different required fields (business registration, EIN, etc.). Contact your Inyo account manager for your tenant-specific KYB configuration.
Compliance Levels
| Level | Typical Required Fields | Description |
|---|---|---|
| Level 0 | (none) | Cannot transact |
| Level 1 | firstName, lastName, address, phoneNumber | Basic KYC |
| Level 2 | SSN, occupation, document ID | Enhanced KYC |
| Level 3 | Proof of source of funds | Full KYC |
These are customizable per tenant. See Trust Level Limits for details.
Best Practices
- Progressive onboarding β Collect only Level 1 fields at signup. Prompt for more data when the user needs higher limits.
- Pre-validate addresses β Use the address check endpoint before creating the sender to avoid holds.
- Sync compliance state β After profile updates, re-check the compliance level to see if it has upgraded.
- Handle restricted users β If a sender is
Restricted, checkGET /participants/{id}/complianceLevelsto understand why and what action is needed.
Related Pages
- Trust Level Limits β Check and upgrade compliance levels
- Verifying Documents β KYC verification sessions and document verification
- Test Data β Sandbox testing scenarios for compliance flows
All Endpoints
| Operation | Method | Endpoint |
|---|---|---|
| Create person (v2) | POST | /organizations/{tenant}/v2/people |
| Update person (v2) | PATCH | /organizations/{tenant}/v2/people/{personId} |
| Create KYC verification session | POST | /organizations/{tenant}/v2/people/{personId}/kycSession |
| Create person (v1 β deprecated) | POST | /organizations/{tenant}/people |
| Update person (v1 β deprecated) | PATCH | /organizations/{tenant}/people/{personId} |
| Get person | GET | /organizations/{tenant}/people/{personId} |
| Get person with details | GET | /organizations/{tenant}/people/{personId}/details |
| Update address | PUT | /organizations/{tenant}/people/{personId}/address |
| Update employer address | PUT | /organizations/{tenant}/people/{personId}/employerAddress |
| Update place of birth | PUT | /organizations/{tenant}/people/{personId}/placeOfBirth |
| Check address | GET | /organizations/{tenant}/addresses/check |
