Customer Tiers (Graded Onboarding)
Individual Customers Only · API v2
Harbor's Graded Onboarding (v2) provides a frictionless, step-by-step verification flow for individual customers. Instead of requiring a complete and comprehensive KYC submission in a single, all-or-nothing call, Graded Onboarding allows your customers to onboard and transact quickly with minimal initial data, and then sequentially upgrade to higher tiers when needed.
Required Step: Customer Creation FirstBefore calling any Graded Onboarding (v2) endpoints, you must first create an individual customer object with
type: "individual"viaPOST /api/v1/customers. This returns thecustomer_uuidused as the path parameter in all onboarding APIs. Please refer to our detailed Customer guide for creation request and response details.
Direct Level 2 Entry AllowedYou can onboard a customer directly into Level 2 in your initial submission. There is no requirement to start with Level 1 or onboard sequentially; if your customer has all documentation ready, you can submit Level 2 onboarding directly.
Jump directly to the Level 1 onboarding JSON payload example for US residents.
Jump directly to the Level 2 onboarding JSON payload example for US residents.
Jump directly to the Level 2 onboarding JSON payload example for non-US residents.
1. V1 vs. V2 Comparison
Before integrating, determine which onboarding flow is right for your application:
| Feature | Standard Onboarding (v1) | Graded Onboarding (v2) |
|---|---|---|
| Target Customers | Business or Individual Customers | Individual Customers Only |
| Submission Model | All-or-nothing (Full KYC collected upfront) | Incremental (Level 1 → Level 2 → Level 3) |
| Typical Use Case | When full, standard individual or corporate verification is required at sign-up. | When you want to "start light" with a low friction sign-up process (Level 1 is US-only). |
Customer Scheme IsolationThis is an architectural choice, not a migration path. Customers onboarded on V1 stay on the V1 scheme; customers who start on V2 remain on V2. You can check which onboarding scheme a customer is assigned to by calling:
GET /api/v1/customers/{uuid}The response will contain either
"kyc_scheme": "v1"or"kyc_scheme": "v2".
Looking for Standard Onboarding (v1)?If your individual customer is using the Standard (v1) scheme, or you prefer a single-call full verification flow, please refer to the Onboard Individual via API guide instead.
2. Customer Levels & Limits
The Graded Onboarding flow assigns individual customers to one of three progressive levels (Level 1, Level 2, or Level 3). Each level has its own residential criteria, required document parts, transaction limits, and supported fiat payment methods.
Detailed Level & Limits GuideFor a comprehensive breakdown of each onboarding level's requirements, exact transaction limit rules, and restricted payment methods (such as the Level 1 trial allowance and Debit Card limitations), please refer to the Customer Level guide.
3. Setup, Endpoints, & Lookups
To avoid duplicate configurations, please refer to our standard integration guidelines:
- Environments & Authentication: See Authentication for Base URLs, authentication headers (
X-API-KEY), and theIdempotency-Keyrequirement. - Customer Creation: Before calling any Graded Onboarding endpoint, you must first create an individual customer with
type: "individual". Please refer to our detailed Customer guide for request and response examples forPOST /api/v1/customers. - Reference-Data Lookups: Some input fields (such as state codes, occupations, and required document parts) only accept dynamically validated options. You must call the lookup APIs documented in Onboarding Meta APIs.
Endpoints (v2)
All Graded Onboarding endpoints use the /api/v2 path prefix:
| Method | Path | Scope | Purpose |
|---|---|---|---|
POST | /api/v2/customers/{uuid}/individual/onboarding | CUSTOMER_CREATE | Initial onboarding submission (Level 1 or Level 2). |
GET | /api/v2/customers/{uuid}/individual/onboarding | CUSTOMER_READ | Poll current onboarding status & details. |
PATCH | /api/v2/customers/{uuid}/individual/onboarding | CUSTOMER_CREATE | Correct submitted data when status is action_required. |
POST | /api/v2/customers/{uuid}/individual/onboarding/upgrade | CUSTOMER_CREATE | Submit a request to upgrade to a higher level. |
4. Submitting Initial Onboarding (POST)
Submit the initial onboarding payload for either Level 1 or Level 2.
4.1 Submitting Level 1 (US Residents Only)
curl -X POST "https://harbor-sandbox.owlpay.com/api/v2/customers/{{customer_uuid}}/individual/onboarding" \
-H "X-API-KEY: ***" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: {{Idempotency-Key}}" \
-d '{
"kyc_level": 1,
"nationality": "US",
"residence": {
"country": "US",
"state": "WA"
}
}'Response: 202 Accepted with a status of processing.
4.2 Submitting Level 2 (US Resident)
{
"kyc_level": 2,
"nationality": "US",
"residence": {
"country": "US",
"state": "WA",
"street": "200 Pine St",
"sub_street": "Apt 5",
"city": "Seattle",
"postal_code": "98101"
},
"occupation": "legislators_and_senior_officials",
"purpose_of_use": ["payments"],
"ssn": "123456789",
"phone_country_code": "US", // Only required if phone is not already on customer record
"phone_number": "+14045550101", // Only required if phone is not already on customer record
"identity_document": {
"type": "PASSPORT",
"country": "US",
"front": "<base64_bytes>"
}
}4.3 Submitting Level 2 (Non-US Resident)
{
"kyc_level": 2,
"nationality": "GB",
"residence": {
"country": "GB",
"street": "10 High St",
"sub_street": "Flat 2",
"city": "London",
"postal_code": "SW1A1AA"
// Note: residence.state must be omitted outside the US (it is rejected, not optional)
},
"occupation": "software_and_applications_developers_and_analysts",
"purpose_of_use": ["payments"],
"tax_id": "AB123456C",
"identity_document": {
"type": "PASSPORT",
"country": "GB",
"front": "<base64_bytes>"
}
}
Fields NOT Collected in V2Graded Onboarding (v2) does not collect the following fields:
applicant,tier,verification_tier,source_of_wealth,source_of_wealth_other,proof_of_address,bank_statement,has_us_bank_account.Sending any of these fields in a v2 onboarding request will result in a 422 Unprocessable Entity error.
5. Polling Status & Lifecycle
You can check the onboarding progress by polling the GET endpoint or subscribing to webhooks.
5.1 Onboarding Statuses
The response JSON shape contains a top-level status:
{
"data": {
"status": "processing",
"kyc_level": null,
"next_level": null,
"transfers_blocked": true,
"rfi_link": null,
"pending_requirements": []
}
}| Status | Meaning | Developer Action |
|---|---|---|
processing | Data is being validated. | Poll or wait for webhook. |
action_required | Submission failed validation. Check pending_requirements for error details. | Prompt user to correct input and send PATCH. |
submitted | Request has been routed for manual compliance review. | Wait. |
verified | Selected level is successfully approved. | Customer is active at this level. |
rejected | Compliance rejected the submission. | Onboarding failed. Check if resubmission is blocked. |
failed | Systemic or document processing error. | Retry/resubmit the onboarding request. |
Onboarding Rejection vs. Customer DeclineA
rejectedonboarding status can typically be corrected and resubmitted unless the customer is completely blocked. If the customer record is officially marked as DECLINED, the status is final. Any subsequent onboarding or upgrade attempts will fail with a 409 conflict (declined_is_final).
5.2 Webhooks
We strongly recommend subscribing to the following webhook events to track real-time onboarding state transitions:
customer_onboarding.submittedcustomer_onboarding.action_requiredcustomer_onboarding.verifiedcustomer_onboarding.rejectedcustomer_onboarding.failed
For setup, see Webhook Subscription.
6. Fixing Validation Errors (PATCH)
When the onboarding status is action_required, you can correct data and resubmit using a PATCH request.
curl -X PATCH "https://harbor-sandbox.owlpay.com/api/v2/customers/{{customer_uuid}}/individual/onboarding" \
-H "X-API-KEY: ***" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: {{Idempotency-Key}}" \
-d '{
"kyc_level": 2,
"nationality": "US",
"residence": {
"country": "US",
"state": "WA",
"street": "200 Pine St (Corrected)",
"sub_street": "Apt 5",
"city": "Seattle",
"postal_code": "98101"
},
"occupation": "legislators_and_senior_officials",
"purpose_of_use": ["payments"],
"ssn": "123456789",
"identity_document": {
"type": "PASSPORT",
"country": "US",
"front": "<base64_bytes>"
}
}'
Critical Rule for PATCHThe PATCH payload replaces the stored onboarding data entirely. Therefore, you must resend all fields (including un-changed fields and base64 files), not just the fields being corrected.
Note: You cannot change the target
kyc_levelusing PATCH; it is locked to the level of the initial submission.
Updated 11 minutes ago