> ## Documentation Index
> Fetch the complete documentation index at: https://developer.fin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Onboarding Individual Customers

> Complete guide to onboarding individual customers with personal details, financial profiles, and identity verification

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:

* **API credentials**: Client ID and secret from the [API Keys](https://orchestration.fin.com/api-keys) section
* **Access token**: Generated via [POST /v1/oauth/token](/api-reference/authentication/issue-a-token)
* **Catalogue data**: Familiarity with [/v1/occupations](/api-reference/catalogue/list-occupations), [/v1/purposes](/api-reference/catalogue/list-account-purposes), and [/v1/source-of-funds](/api-reference/catalogue/list-source-of-funds) endpoints

## Onboarding Steps

| Step                    | Endpoint                                                                                                                                                                                                                                       | Description                                                     |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| 1. Fetch Catalogue Data | [GET /v1/occupations](/api-reference/catalogue/list-occupations), [GET /v1/purposes?type=INDIVIDUAL](/api-reference/catalogue/list-account-purposes), [GET /v1/source-of-funds?type=INDIVIDUAL](/api-reference/catalogue/list-source-of-funds) | Retrieve valid IDs for occupations, purposes, and fund sources  |
| 2. Create Customer      | [POST /v2/customers/individual](/api-reference/customers/create-individual-customer-v2)                                                                                                                                                        | Submit personal details, address, and financial profile         |
| 3. Upload Documents     | [POST /v1/customers/upload](/api-reference/customers/upload-document)                                                                                                                                                                          | Upload identity, selfie, and address proof files                |
| 4. Attach Documents     | Link uploaded documents to the customer (processed asynchronously)                                                                                                                                                                             |                                                                 |
| 5. Monitor Status       | Webhooks: `customer.status`                                                                                                                                                                                                                    | Track 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.

```json theme={null}
{
  "verification_type": "STANDARD"
}
```

<Warning>
  **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"`
</Warning>

### 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:**

| Field                   | Type           | Required    | Description                                                                       | Example                      |
| ----------------------- | -------------- | ----------- | --------------------------------------------------------------------------------- | ---------------------------- |
| `first_name`            | string         | Yes         | Legal first name as shown on ID                                                   | `"María"`                    |
| `first_name_en`         | string         | Conditional | English transliteration. Required if `first_name` contains non-ASCII characters.  | `"Maria"`                    |
| `middle_name`           | string         | No          | Middle name                                                                       | `"Elena"`                    |
| `middle_name_en`        | string         | Conditional | English transliteration. Required if `middle_name` contains non-ASCII characters. | `"Elena"`                    |
| `last_name`             | string         | Yes         | Legal last name as shown on ID                                                    | `"García"`                   |
| `last_name_en`          | string         | Conditional | English transliteration. Required if `last_name` contains non-ASCII characters.   | `"Garcia"`                   |
| `dob`                   | string (date)  | Yes         | Date of birth in YYYY-MM-DD format. Age must be between 18 and 120.               | `"1990-04-15"`               |
| `email`                 | string (email) | Yes         | Personal email address - **must be all lowercase**                                | `"maria.garcia@example.com"` |
| `phone`                 | string         | Yes         | Phone number in E.164 format                                                      | `"+14155552671"`             |
| `country_of_residence`  | string         | Yes         | ISO Alpha-3 country code where person resides                                     | `"USA"`                      |
| `primary_nationality`   | string         | Yes         | ISO Alpha-3 country code of primary citizenship                                   | `"USA"`                      |
| `secondary_nationality` | string         | No          | ISO Alpha-3 country code of secondary citizenship                                 | `"MEX"`                      |
| `gender`                | string         | No          | `MALE` or `FEMALE`                                                                | `"FEMALE"`                   |
| `tax_info`              | array          | Yes         | Tax identification documents (see below)                                          | --                           |

<Warning>
  Email must be **all lowercase** or validation will fail. Convert to lowercase before sending: `maria.garcia@example.com` ✓ not `Maria.Garcia@Example.com` ✗
</Warning>

***

#### Tax Info Array

Each entry in `tax_info` must have a unique `document_id`.

| Field           | Type   | Required | Description                            | Example         |
| --------------- | ------ | -------- | -------------------------------------- | --------------- |
| `country_code`  | string | Yes      | ISO Alpha-3 country code               | `"USA"`         |
| `document_type` | string | Yes      | Tax document type (e.g., `SSN`, `TIN`) | `"SSN"`         |
| `document_id`   | string | Yes      | Tax identification number              | `"123-45-6789"` |

<Tip>
  **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
</Tip>

<Note>
  **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.
</Note>

**Example:**

```json theme={null}
{
  "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:**

| Field              | Type   | Required    | Description                                                                         | Example               |
| ------------------ | ------ | ----------- | ----------------------------------------------------------------------------------- | --------------------- |
| `street_line_1`    | string | Yes         | Primary street address                                                              | `"123 Market Street"` |
| `street_line_1_en` | string | Conditional | English transliteration. Required if `street_line_1` contains non-ASCII characters. | `"123 Market Street"` |
| `street_line_2`    | string | No          | Apartment, suite, unit, etc.                                                        | `"Apt 4B"`            |
| `street_line_2_en` | string | Conditional | English transliteration. Required if `street_line_2` contains non-ASCII characters. | `"Apt 4B"`            |
| `city`             | string | Yes         | City name                                                                           | `"San Francisco"`     |
| `subdivision_code` | string | Yes         | ISO 3166-2 subdivision code                                                         | `"US-CA"`             |
| `postal_code`      | string | Yes         | Postal or ZIP code                                                                  | `"94103"`             |
| `country`          | string | Yes         | ISO Alpha-3 country code. **Must match `country_of_residence`.**                    | `"USA"`               |

<Tip>
  **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/](/api-reference/catalogue/list-subdivisions){country_code}[/subdivisions](/api-reference/catalogue/list-subdivisions).
</Tip>

<Tip>
  **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`.
</Tip>

**Example:**

```json theme={null}
{
  "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:**

| Field                         | Type       | Required | Description                                                              | How to Get Value                                                                         |
| ----------------------------- | ---------- | -------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `employment_status`           | string     | Yes      | One of: `EMPLOYED`, `SELF_EMPLOYED`, `RETIRED`, `STUDENT`, `UNEMPLOYED`  | Select from enum                                                                         |
| `occupation_id`               | integer    | Yes      | Customer's occupation                                                    | [GET /v1/occupations](/api-reference/catalogue/list-occupations)                         |
| `purpose_id`                  | integer    | Yes      | Purpose of using the service                                             | [GET /v1/purposes?type=INDIVIDUAL](/api-reference/catalogue/list-account-purposes)       |
| `purpose_remarks`             | string     | No       | Free-text description of the purpose                                     | User input                                                                               |
| `source_of_fund_ids`          | integer\[] | Yes      | Source(s) of funds (supports multiple)                                   | [GET /v1/source-of-funds?type=INDIVIDUAL](/api-reference/catalogue/list-source-of-funds) |
| `source_of_funds_description` | string     | No       | Free-text description of fund sources                                    | User input                                                                               |
| `monthly_volume_usd`          | integer    | Yes      | Expected monthly transaction volume in **USD** (not cents). Accepts `0`. | User estimate: `5000`                                                                    |

<Note>
  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`.
</Note>

<Tip>
  **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`.
</Tip>

**Example:**

```json theme={null}
{
  "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:

```json theme={null}
{
  "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:

```bash theme={null}
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, PNG

**Response:**

```json theme={null}
{
  "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.

<Note>
  * 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.
</Note>

```bash theme={null}
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):**

```json theme={null}
{
  "data": {
    "customer_id": "55bd6b4e-c20a-4cc8-9535-91d5557a67d9"
  },
  "meta": null
}
```

<Warning>
  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.
</Warning>

#### Identity Document Types & Side Requirements

| Type               | Files | Sides Required           | `state` field                                    |
| ------------------ | ----- | ------------------------ | ------------------------------------------------ |
| `PASSPORT`         | 1     | Optional                 | Forbidden                                        |
| `NATIONAL_ID`      | 2     | One `FRONT` + one `BACK` | Forbidden                                        |
| `DRIVERS_LICENSE`  | 2     | One `FRONT` + one `BACK` | Required if country is `USA`, optional otherwise |
| `RESIDENCE_PERMIT` | 2     | One `FRONT` + one `BACK` | Forbidden                                        |
| `SELFIE`           | 1     | Optional                 | N/A                                              |

<Note>
  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.
</Note>

#### Address Proof Types

| Type                | Description                                |
| ------------------- | ------------------------------------------ |
| `UTILITY_BILL`      | Recent utility bill (gas, electric, water) |
| `BANK_STATEMENT`    | Bank statement (within the last 3 months)  |
| `GOVERNMENT_LETTER` | Official government correspondence         |

Exactly **one** `address_documents` entry is required. The `country` on the address document must match the customer's `country_of_residence`.

<Tip>
  **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)
</Tip>

#### 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:**

<Frame>
  <img src="https://mintcdn.com/fincom/7n-7PW9mg2_I4Tw7/images/individual-status-lifecycle.png?fit=max&auto=format&n=7n-7PW9mg2_I4Tw7&q=85&s=ee017bf1c05124a074dd17da4255b49c" alt="Individual Status Lifecycle" width="1440" height="1504" data-path="images/individual-status-lifecycle.png" />
</Frame>

| Status            | Description                                                    |
| ----------------- | -------------------------------------------------------------- |
| `INCOMPLETE`      | Customer created but documents not yet attached                |
| `REVIEWING`       | Documents submitted and under compliance review                |
| `APPROVED`        | Verification complete, customer can transact                   |
| `ACTION_REQUIRED` | Additional documents or corrections needed (re-attach allowed) |
| `ON_HOLD`         | Additional information required via RFI                        |
| `REJECTED`        | Verification 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](/guides/webhooks/verifying-webhooks) for setup.

***

## Error Response Examples

**Email validation error (not lowercase):**

```json theme={null}
{
  "message": "Validation failed",
  "errors": {
    "basic_info.email": ["Email must be all lowercase"]
  }
}
```

**RELIANCE not enabled:**

```json theme={null}
{
  "message": "RELIANCE is not available for your client"
}
```

**Address country mismatch:**

```json theme={null}
{
  "message": "Validation failed",
  "errors": {
    "address.country": ["Must match basic_info.country_of_residence"]
  }
}
```

**Concurrent attach conflict (409):**

```json theme={null}
{
  "error": {
    "code": "conflict",
    "message": "An attach request is already in progress for this customer"
  }
}
```

**Customer not eligible for attach (403):**

```json theme={null}
{
  "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: `INCOMPLETE` → `REVIEWING` → `APPROVED`
* 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](/guides/webhooks/verifying-webhooks) 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:

* See [Beneficiary Account Validation](/bank-account-and-routing-validation-rules)
* Review [Beneficiary Relationships](/guides/beneficiaries/sender-and-receiver-relationships)

***

## V1 to V2 Migration Summary

| Area                 | V1                                     | V2                                                                   |
| -------------------- | -------------------------------------- | -------------------------------------------------------------------- |
| Create endpoint      | `POST /v1/customers/individual`        | `POST /v2/customers/individual`                                      |
| `verification_type`  | Optional (defaults to STANDARD)        | Required                                                             |
| Name fields          | `first_name`, `last_name`              | Adds `middle_name` + `_en` transliteration fields                    |
| Nationality          | `nationality`                          | `primary_nationality` + optional `secondary_nationality`             |
| Gender               | Not supported                          | Optional `gender` field                                              |
| Tax ID               | Single `tin` string                    | `tax_info` array with `country_code`, `document_type`, `document_id` |
| Address street       | Single `street` field                  | `street_line_1` + `street_line_2` + `_en` fields                     |
| Address state        | `state`                                | `subdivision_code`                                                   |
| Address country      | No validation against residence        | Must match `country_of_residence`                                    |
| Employment           | Not supported                          | Required `employment_status` enum                                    |
| Source of funds      | Single `source_of_fund_id`             | Array `source_of_fund_ids` + `source_of_funds_description`           |
| Purpose              | `purpose_id` only                      | `purpose_id` + optional `purpose_remarks`                            |
| Attach endpoint      | `POST /v1/customers/individual/attach` | `POST /v2/customers/{customer_id}/individual/attach`                 |
| Attach body          | `customer_id` in body                  | `customer_id` in URL path                                            |
| Identity docs        | `proof_of_identity` object             | `identifying_documents` array                                        |
| Address docs         | `proof_of_address` object              | `address_documents` array (max 1 entry)                              |
| Selfie               | Not supported                          | `SELFIE` type in `identifying_documents`                             |
| Residence permit     | Not supported as ID type               | `RESIDENCE_PERMIT` type supported                                    |
| Address proof types  | 8 types                                | 3 types: `UTILITY_BILL`, `BANK_STATEMENT`, `GOVERNMENT_LETTER`       |
| `tos_policies_value` | Required in attach body                | Not required in attach body                                          |
| Processing           | Synchronous                            | Asynchronous (200 = queued)                                          |
| Concurrency          | No guard                               | 409 if attach already in flight                                      |

***

## Common Pitfalls & Solutions

| Pitfall                               | Solution                                                                                                               |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Email validation fails**            | Ensure email is **all lowercase** before sending: `maria.garcia@example.com` ✓ not `Maria.Garcia@Example.com` ✗        |
| **Address country mismatch**          | `address.country` must exactly match `basic_info.country_of_residence`.                                                |
| **RELIANCE 423 error**                | RELIANCE verification must be enabled for your client. Contact support or use `STANDARD`.                              |
| **Non-ASCII without `_en` field**     | If name or address contains non-Latin characters, provide the transliterated value in the `_en` counterpart field.     |
| **Subdivision code validation fails** |                                                                                                                        |
| **Phone format rejected**             | Use E.164 format with country code: `+14155552671`, not `(415) 555-2671`.                                              |
| **Monthly volume rejected**           | Provide amount in USD as integer (not cents): `5000` for \$5,000, not `500000`.                                        |
| **Missing document sides**            | For `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 document**         | `expiry_date` must be in the future. Ensure documents are not expired before submitting.                               |
| **Selfie missing**                    | If your client requires selfie, include exactly one `SELFIE` entry in `identifying_documents`.                         |
| **Duplicate file URIs**               | File URIs must be unique across the request (SELFIE excluded). Don't reuse the same URI for identity and address docs. |
