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 First

Before calling any Graded Onboarding (v2) endpoints, you must first create an individual customer object with type: "individual" via POST /api/v1/customers. This returns the customer_uuid used 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 Allowed

You 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.


1. V1 vs. V2 Comparison

Before integrating, determine which onboarding flow is right for your application:

FeatureStandard Onboarding (v1)Graded Onboarding (v2)
Target CustomersBusiness or Individual CustomersIndividual Customers Only
Submission ModelAll-or-nothing (Full KYC collected upfront)Incremental (Level 1 → Level 2 → Level 3)
Typical Use CaseWhen 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 Isolation

This 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 Guide

For 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 the Idempotency-Key requirement.
  • 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 for POST /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:

MethodPathScopePurpose
POST/api/v2/customers/{uuid}/individual/onboardingCUSTOMER_CREATEInitial onboarding submission (Level 1 or Level 2).
GET/api/v2/customers/{uuid}/individual/onboardingCUSTOMER_READPoll current onboarding status & details.
PATCH/api/v2/customers/{uuid}/individual/onboardingCUSTOMER_CREATECorrect submitted data when status is action_required.
POST/api/v2/customers/{uuid}/individual/onboarding/upgradeCUSTOMER_CREATESubmit 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 V2

Graded 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": []
  }
}
StatusMeaningDeveloper Action
processingData is being validated.Poll or wait for webhook.
action_requiredSubmission failed validation. Check pending_requirements for error details.Prompt user to correct input and send PATCH.
submittedRequest has been routed for manual compliance review.Wait.
verifiedSelected level is successfully approved.Customer is active at this level.
rejectedCompliance rejected the submission.Onboarding failed. Check if resubmission is blocked.
failedSystemic or document processing error.Retry/resubmit the onboarding request.
🚧

Onboarding Rejection vs. Customer Decline

A rejected onboarding 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.submitted
  • customer_onboarding.action_required
  • customer_onboarding.verified
  • customer_onboarding.rejected
  • customer_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 PATCH

The 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_level using PATCH; it is locked to the level of the initial submission.


Did this page help you?