Skip to main content
Onboard individual customers to enable cross-border payments and payouts through Fin.com’s platform. This guide walks you through creating individual customer profiles, uploading verification documents, and managing the compliance workflow using the V2 API.

Prerequisites

Before you begin, ensure you have:

Onboarding Steps

StepEndpointDescription
1. Fetch Catalogue DataGET /v1/occupations, GET /v1/purposes?type=INDIVIDUAL, GET /v1/source-of-funds?type=INDIVIDUALRetrieve valid IDs for occupations, purposes, and fund sources
2. Create CustomerPOST /v2/customers/individualSubmit personal details, address, and financial profile
3. Upload DocumentsPOST /v1/customers/uploadUpload identity, selfie, and address proof files
4. Attach DocumentsLink uploaded documents to the customer (processed asynchronously)
5. Monitor StatusWebhooks: customer.statusTrack verification progress (INCOMPLETE → REVIEWING → APPROVED)

Request Body Structure

Verification Type (Required)

Verification type determines how customer identity is validated. STANDARD uses traditional document verification. On RELIANCE, Fin.com relies on your KYC. Please contact our compliance team to know more.
{
  "verification_type": "STANDARD"
}
RELIANCE verification must be explicitly enabled for your client. If not available, you’ll receive a 423 error with the message: "RELIANCE is not available for your client"

Basic Information (Required)

Personal details exactly as shown on identity documents. All fields must use only English (Latin) characters. If any field contains non-ASCII characters, provide a transliterated value in the corresponding _en field.
Fields:
FieldTypeRequiredDescriptionExample
first_namestringYesLegal first name as shown on ID"María"
first_name_enstringConditionalEnglish transliteration. Required if first_name contains non-ASCII characters."Maria"
middle_namestringNoMiddle name"Elena"
middle_name_enstringConditionalEnglish transliteration. Required if middle_name contains non-ASCII characters."Elena"
last_namestringYesLegal last name as shown on ID"García"
last_name_enstringConditionalEnglish transliteration. Required if last_name contains non-ASCII characters."Garcia"
dobstring (date)YesDate of birth in YYYY-MM-DD format. Age must be between 18 and 120."1990-04-15"
emailstring (email)YesPersonal email address - must be all lowercase"maria.garcia@example.com"
phonestringYesPhone number in E.164 format"+14155552671"
country_of_residencestringYesISO Alpha-3 country code where person resides"USA"
primary_nationalitystringYesISO Alpha-3 country code of primary citizenship"USA"
secondary_nationalitystringNoISO Alpha-3 country code of secondary citizenship"MEX"
genderstringNoMALE or FEMALE"FEMALE"
tax_infoarrayYesTax identification documents (see below)
Email must be all lowercase or validation will fail. Convert to lowercase before sending: maria.garcia@example.com ✓ not Maria.Garcia@Example.com

Tax Info Array

Each entry in tax_info must have a unique document_id.
FieldTypeRequiredDescriptionExample
country_codestringYesISO Alpha-3 country code"USA"
document_typestringYesTax document type (e.g., SSN, TIN)"SSN"
document_idstringYesTax identification number"123-45-6789"
TIN Format by Country:
  • USA: Social Security Number in format xxx-xx-xxxx (e.g., 123-45-6789)
  • Other countries: Must use the country’s official Tax Identification Number format
V2 Change: tax_info replaces tin. V1 used a single tin string field. V2 uses a tax_info array, which supports multiple tax documents across different countries.
Example:
{
  "basic_info": {
    "first_name": "Maria",
    "middle_name": "Elena",
    "last_name": "Garcia",
    "dob": "1990-04-15",
    "email": "maria.garcia@example.com",
    "phone": "+14155552671",
    "country_of_residence": "USA",
    "primary_nationality": "USA",
    "secondary_nationality": "MEX",
    "gender": "FEMALE",
    "tax_info": [
      {
        "country_code": "USA",
        "document_type": "SSN",
        "document_id": "123-45-6789"
      }
    ]
  }
}

Address (Required)

Current residential address of the customer. The country field must match basic_info.country_of_residence.
Fields:
FieldTypeRequiredDescriptionExample
street_line_1stringYesPrimary street address"123 Market Street"
street_line_1_enstringConditionalEnglish transliteration. Required if street_line_1 contains non-ASCII characters."123 Market Street"
street_line_2stringNoApartment, suite, unit, etc."Apt 4B"
street_line_2_enstringConditionalEnglish transliteration. Required if street_line_2 contains non-ASCII characters."Apt 4B"
citystringYesCity name"San Francisco"
subdivision_codestringYesISO 3166-2 subdivision code"US-CA"
postal_codestringYesPostal or ZIP code"94103"
countrystringYesISO Alpha-3 country code. Must match country_of_residence."USA"
Subdivision Code Format: Use ISO 3166-2 codes from the catalogue API. For example, use US-CA instead of CA for California, or GB-ENG instead of England. Fetch valid codes from /v1/countries//subdivisions.
V2 Change: Address fields. V1 used a single street field. V2 splits this into street_line_1 and street_line_2. The state field has been renamed to subdivision_code.
Example:
{
  "address": {
    "street_line_1": "123 Market Street",
    "street_line_2": "Apt 4B",
    "city": "San Francisco",
    "subdivision_code": "US-CA",
    "postal_code": "94103",
    "country": "USA"
  }
}

Financial Profile (Required)

Describes employment status, occupation, transaction purpose, volume, and fund sources. Use catalogue endpoints to fetch valid IDs.
Fields:
FieldTypeRequiredDescriptionHow to Get Value
employment_statusstringYesOne of: EMPLOYED, SELF_EMPLOYED, RETIRED, STUDENT, UNEMPLOYEDSelect from enum
occupation_idintegerYesCustomer’s occupationGET /v1/occupations
purpose_idintegerYesPurpose of using the serviceGET /v1/purposes?type=INDIVIDUAL
purpose_remarksstringNoFree-text description of the purposeUser input
source_of_fund_idsinteger[]YesSource(s) of funds (supports multiple)GET /v1/source-of-funds?type=INDIVIDUAL
source_of_funds_descriptionstringNoFree-text description of fund sourcesUser input
monthly_volume_usdintegerYesExpected monthly transaction volume in USD (not cents). Accepts 0.User estimate: 5000
When fetching catalogue data for individual customers, use the ?type=INDIVIDUAL query parameter to get the correct options for purpose_id and source_of_fund_ids.
V2 Change: Multiple fund sources. V1 accepted a single source_of_fund_id integer. V2 uses source_of_fund_ids as an array, allowing multiple sources. V2 also adds employment_status (required), purpose_remarks, and source_of_funds_description.
Example:
{
  "financial_profile": {
    "employment_status": "EMPLOYED",
    "occupation_id": 42,
    "purpose_id": 3,
    "purpose_remarks": "Personal remittances to family",
    "source_of_fund_ids": [1, 5],
    "source_of_funds_description": "Monthly salary from employment",
    "monthly_volume_usd": 5000
  }
}

Metadata (Optional)

Custom key-value pairs for internal tracking:
{
  "meta_data": {
    "reference": "client-ref-abc-001"
  }
}

Document Upload & Attachment

After creating the individual customer, you must upload and attach verification documents.

Step 1: Upload Documents

Upload files using multipart/form-data:
curl --request POST \
  --url https://sandbox.api.fin.com/v1/customers/upload \
  --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'customer_id=55bd6b4e-c20a-4cc8-9535-91d5557a67d9' \
  --form 'file1=@/path/to/selfie.jpg' \
  --form 'file2=@/path/to/license_front.pdf' \
  --form 'file3=@/path/to/license_back.pdf' \
  --form 'file4=@/path/to/bank_statement.pdf'
Allowed file types: PDF, JPG, JPEG, PNGResponse:
{
  "data": {
    "files": [
      {"file1": "/AbAcQ4hn_0652746727637.pdf"},
      {"file2": "/AbAcQ4hn_0652746727638.pdf"},
      {"file3": "/XyZ123mn_0652746727639.pdf"},
      {"file4": "/PoAdef45_0652746727640.pdf"}
    ]
  }
}
Save these URIs - you’ll use them in the attachment request.

Step 2: Attach Documents

In V2, the customer_id moves to the URL path. The request body uses identifying_documents and address_documents arrays instead of V1’s proof_of_identity and proof_of_address objects.
  • The customer must be in INCOMPLETE or ACTION_REQUIRED status. Only one attach request can be in flight per customer. A second concurrent request returns 409.
  • The tos_policies_value should be parsed from the tos_policies_url query parameter returned when creating the customer. Providing this value signifies that the customer was shown the terms and accepted them.
curl --request POST \
  --url https://sandbox.api.fin.com/v2/customers/55bd6b4e-c20a-4cc8-9535-91d5557a67d9/individual/attach \
  --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "identifying_documents": [
    {
      "type": "SELFIE",
      "files": [
        {"uri": "/AbAcQ4hn_0652746727637.pdf"}
      ]
    },
    {
      "type": "DRIVERS_LICENSE",
      "number": "DL987654321",
      "country": "USA",
      "state": "US-CA",
      "issue_date": "2019-06-01",
      "expiry_date": "2029-06-01",
      "files": [
        {"side": "FRONT", "uri": "/AbAcQ4hn_0652746727638.pdf"},
        {"side": "BACK", "uri": "/XyZ123mn_0652746727639.pdf"}
      ]
    }
  ],
  "address_documents": [
    {
      "type": "BANK_STATEMENT",
      "country": "USA",
      "files": [
        {"uri": "/PoAdef45_0652746727640.pdf"}
      ]
    }
  ],
 "tos_policies_value": "e9414388-fbdf-4407-b5c2-bc39eae3645b"
}'
Response (200 - queued for async processing):
{
  "data": {
    "customer_id": "55bd6b4e-c20a-4cc8-9535-91d5557a67d9"
  },
  "meta": null
}
V2 document attachment is asynchronous. A 200 response means the request is validated and queued, not that processing is complete. Listen for customer.status webhooks to track progress.

Identity Document Types & Side Requirements

TypeFilesSides Requiredstate field
PASSPORT1OptionalForbidden
NATIONAL_ID2One FRONT + one BACKForbidden
DRIVERS_LICENSE2One FRONT + one BACKRequired if country is USA, optional otherwise
RESIDENCE_PERMIT2One FRONT + one BACKForbidden
SELFIE1OptionalN/A
At most one non-SELFIE identity document may be included per request. A SELFIE entry may be required depending on your client configuration. When required, include exactly one SELFIE entry with at least one file.

Address Proof Types

TypeDescription
UTILITY_BILLRecent utility bill (gas, electric, water)
BANK_STATEMENTBank statement (within the last 3 months)
GOVERNMENT_LETTEROfficial government correspondence
Exactly one address_documents entry is required. The country on the address document must match the customer’s country_of_residence.
Proof of Address Requirements:
  • Document must show the customer’s full name and complete address
  • Address must match the address provided in the customer creation request
  • Document should be issued within the last 90 days (for utility bills, bank statements, and government letters)

Key Rules

  • File URIs must be unique across the entire reques and must belong to this customer.
  • expiry_date is required for all identity document types except SELFIE and must be in the future.

Customer Status & Webhooks

After document submission, customers go through a verification workflow:Status Lifecycle:
Individual Status Lifecycle
StatusDescription
INCOMPLETECustomer created but documents not yet attached
REVIEWINGDocuments submitted and under compliance review
APPROVEDVerification complete, customer can transact
ACTION_REQUIREDAdditional documents or corrections needed (re-attach allowed)
ON_HOLDAdditional information required via RFI
REJECTEDVerification failed, see rejection reason
Webhook Events:
  • customer.created - Fired when a customer is created
  • customer.status - Fired when status changes
Subscribe to webhooks to automate your onboarding flow. See Verifying Webhooks for setup.

Error Response Examples

Email validation error (not lowercase):
{
  "message": "Validation failed",
  "errors": {
    "basic_info.email": ["Email must be all lowercase"]
  }
}
RELIANCE not enabled:
{
  "message": "RELIANCE is not available for your client"
}
Address country mismatch:
{
  "message": "Validation failed",
  "errors": {
    "address.country": ["Must match basic_info.country_of_residence"]
  }
}
Concurrent attach conflict (409):
{
  "error": {
    "code": "conflict",
    "message": "An attach request is already in progress for this customer"
  }
}
Customer not eligible for attach (403):
{
  "error": {
    "code": "forbidden",
    "message": "Customer is not eligible for this operation"
  }
}

What’s Next?

You’ve successfully created an individual customer using V2. Here’s what to do next:

1. Monitor Verification Status

Listen for webhook events to track verification progress:
  • Subscribe to customer.created and customer.status webhooks
  • Handle status transitions: INCOMPLETEREVIEWINGAPPROVED
  • For ACTION_REQUIRED statuses, re-submit corrected documents via the attach endpoint
  • For ON_HOLD statuses, respond to RFIs (Requests for Information) via email or Slack with additional documents
  • See Webhook Verification for implementation details

2. Test Edge Cases

Validate your integration handles common errors:
  • ✓ Email with uppercase characters
  • address.country not matching country_of_residence
  • ✓ Non-ASCII characters without _en transliteration fields
  • ✓ Missing required fields
  • ✓ RELIANCE verification when not enabled
  • ✓ Concurrent attach requests (409)
  • ✓ Expired identity documents
  • ✓ Duplicate file URIs across documents

3. Production Checklist

Before going live, ensure you have:
  • Implemented webhook handling for status updates
  • Added proper error handling for all failure scenarios (400, 401, 403, 409, 422)
  • Client-side validation for email lowercase and tax document format
  • Fetched and cached catalogue data (occupations, purposes, source-of-funds)
  • Implemented document upload UI/flow including selfie capture
  • Set up monitoring for failed verifications
  • Tested the complete workflow end-to-end

4. Create Beneficiaries

Once your individual customer is approved, you can create beneficiaries for payouts:

V1 to V2 Migration Summary

AreaV1V2
Create endpointPOST /v1/customers/individualPOST /v2/customers/individual
verification_typeOptional (defaults to STANDARD)Required
Name fieldsfirst_name, last_nameAdds middle_name + _en transliteration fields
Nationalitynationalityprimary_nationality + optional secondary_nationality
GenderNot supportedOptional gender field
Tax IDSingle tin stringtax_info array with country_code, document_type, document_id
Address streetSingle street fieldstreet_line_1 + street_line_2 + _en fields
Address statestatesubdivision_code
Address countryNo validation against residenceMust match country_of_residence
EmploymentNot supportedRequired employment_status enum
Source of fundsSingle source_of_fund_idArray source_of_fund_ids + source_of_funds_description
Purposepurpose_id onlypurpose_id + optional purpose_remarks
Attach endpointPOST /v1/customers/individual/attachPOST /v2/customers/{customer_id}/individual/attach
Attach bodycustomer_id in bodycustomer_id in URL path
Identity docsproof_of_identity objectidentifying_documents array
Address docsproof_of_address objectaddress_documents array (max 1 entry)
SelfieNot supportedSELFIE type in identifying_documents
Residence permitNot supported as ID typeRESIDENCE_PERMIT type supported
Address proof types8 types3 types: UTILITY_BILL, BANK_STATEMENT, GOVERNMENT_LETTER
tos_policies_valueRequired in attach bodyNot required in attach body
ProcessingSynchronousAsynchronous (200 = queued)
ConcurrencyNo guard409 if attach already in flight

Common Pitfalls & Solutions

PitfallSolution
Email validation failsEnsure email is all lowercase before sending: maria.garcia@example.com ✓ not Maria.Garcia@Example.com
Address country mismatchaddress.country must exactly match basic_info.country_of_residence.
RELIANCE 423 errorRELIANCE verification must be enabled for your client. Contact support or use STANDARD.
Non-ASCII without _en fieldIf name or address contains non-Latin characters, provide the transliterated value in the _en counterpart field.
Subdivision code validation fails
Phone format rejectedUse E.164 format with country code: +14155552671, not (415) 555-2671.
Monthly volume rejectedProvide amount in USD as integer (not cents): 5000 for $5,000, not 500000.
Missing document sidesFor NATIONAL_ID, DRIVERS_LICENSE, and RESIDENCE_PERMIT, include both FRONT and BACK files.
Concurrent attach fails (409)Only one attach per customer at a time. Wait for the first to complete before retrying.
Expired identity documentexpiry_date must be in the future. Ensure documents are not expired before submitting.
Selfie missingIf your client requires selfie, include exactly one SELFIE entry in identifying_documents.
Duplicate file URIsFile URIs must be unique across the request (SELFIE excluded). Don’t reuse the same URI for identity and address docs.