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

# Onboard customers

> Create a business client, complete KYB verification, and get an active stablecoin account using the End User Onboarding API in sandbox

Walk through the full onboarding flow: create a business client, complete KYB
verification, upload documents, submit the application, and retrieve your active
stablecoin account.

<Note>
  The Digital Asset Accounts API base URL is `https://api-sandbox.circle.com` for
  sandbox and `https://api.circle.com` for production. Set your API key in the
  `Authorization` header using the format `Bearer YOUR_API_KEY`. See
  [Sandbox environment](/digital-asset-accounts/references/testing-in-sandbox) and
  [Going to production](/digital-asset-accounts/references/going-to-production)
  for environment details.
</Note>

## Prerequisites

Before you begin this quickstart, ensure you've:

* Requested and received Digital Asset Accounts sandbox access from your Circle
  representative. See
  [Sandbox environment](/digital-asset-accounts/references/testing-in-sandbox)
  for details.
* Obtained an API key for Digital Asset Accounts from your Circle
  representative.
* (Recommended) Configured a
  [webhook subscription](/api-reference/webhook-endpoints#v1-notifications) for
  tracking asynchronous events.

## Step 1: Create a business client

Create a new business client using the End User Onboarding API. Each client
represents a business entity that goes through KYB verification.

```shell theme={null}
curl --request POST \
  --url https://api-sandbox.circle.com/v1/partner/clients \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "clientName": "My Company ABC1",
    "country": "US",
    "clientType": "business",
    "businessDetails": {
      "natureOfBusiness": "paymentProcessorPlatform",
      "institutionType": "privateCo"
    }
  }'
```

Replace `YOUR_API_KEY` with your Bearer token. Use a unique `clientName` for
each new client, because the API rejects duplicate names.

<Warning>
  **Keep your API keys safe.** Never share your API key or record it in a publicly
  accessible medium such as client-side code or public repositories.
</Warning>

Save the `clientEntityId` and `applicationId` from the response. You need both
values for the remaining steps.

```json theme={null}
{
  "data": {
    "clientEntityId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "applicationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  }
}
```

## Step 2: Complete business information

Fill out the required business information sections. Replace `{applicationId}`
with the value from step 1 in all of the following requests.

### 2.1. Basic business info

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/basicBusinessInfo \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "businessWebsite": "https://mycompany.example.com",
    "businessWebsiteProvided": true,
    "businessModelDescription": "Digital payments platform for stablecoin transfers",
    "customerTypesDescription": "Small businesses and individual consumers in the US",
    "productsAndServicesDescription": "USDC payments, deposits, and withdrawals"
  }'
```

### 2.2. Business address

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/physicalBusinessAddress \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "physicalAddressLine1": "1 Main St",
    "physicalAddressCity": "New York",
    "physicalAddressState": "NY",
    "physicalAddressPostalCode": "10001",
    "physicalAddressCountry": "US",
    "businessAddressRemote": false,
    "physicalAddressProofOfAddress": []
  }'
```

### 2.3. Business registration

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/businessRegistrationDetails \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "businessName": "My Company ABC1",
    "businessNameDifferent": false,
    "registrationNumber": "00-0000000",
    "taxId": "00-0000000",
    "countryOfFormation": "US",
    "businessStateOfRegistrationOfFormation": "NY",
    "dateOfFormation": "2010-01-01"
  }'
```

<Note>
  The `businessName` value must match the `clientName` you used in step 1.
</Note>

## Step 3: Complete the remaining KYB sections

Six more sections need data before you can submit the application. The following
calls use placeholder data that is valid for sandbox testing.

### 3.1. Entity operations

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/entityOperations \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "entityServesCustomers": true,
    "countriesWithMostCustomers": ["US"],
    "countriesWithPhysicalPresence": ["US"],
    "businessAcceptsPrivacyCoin": false,
    "customerBaseByType": { "individuals": "70", "businesses": "30" }
  }'
```

### 3.2. Compliance details

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/financialCrimesComplianceDetails \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "complianceOfficerDetailsProvided": false,
    "noComplianceOfficerDetailsReason": "Outsourced to external compliance firm",
    "lastYearAmlProgramProvided": false,
    "noLastYearAmlProgramReason": "Entity less than 1 year old",
    "amlTestingReportProvided": false,
    "noAmlTestingReportReason": "Entity less than 1 year old"
  }'
```

### 3.3. Licensing

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/licensingAndRegistration \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "licenseAndRegistrationRequired": false,
    "noLicenseAndRegistrationRequiredReason": "Not required in jurisdiction"
  }'
```

### 3.4. Beneficial owners

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/beneficialOwnersDetails \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "beneficialOwnersExist": false,
    "beneficialOwnershipExempted": true,
    "beneficialOwnershipExemptionReason": "Single owner private company"
  }'
```

### 3.5. Intended use of account

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/intendedUseOfAccount \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "accountPurpose": ["paymentProcessingPlatform"],
    "accountPurposeDescription": "USDC payments and transfers",
    "expectedMonthlyFiatActivity": "from0to100k",
    "expectedMonthlyCryptoActivity": "from0to100k",
    "expectedProductsForUsage": ["circleMint"],
    "sourceOfFunds": ["businessOperatingFunds"],
    "sourceOfFundsDescription": "Revenue from platform services",
    "financialDocumentsProvided": false,
    "noFinancialDocumentReason": "New entity",
    "assetsUnderManagement": "from0to10m",
    "bankBrokerageCryptoStatement": []
  }'
```

### 3.6. Control person

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/individualWithSignificantControlPersons \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '[{
    "controllerFirstName": "Jane",
    "controllerLastName": "Smith",
    "controllerDob": "1985-06-15",
    "controllerCitizenship": ["US"],
    "controllerIdentificationNumber": "000-00-0000",
    "controllerJobTitle": "Director",
    "controllerLine1": "1 Main St",
    "controllerCity": "New York",
    "controllerState": "NY",
    "controllerPostalCode": "10001",
    "controllerCountry": "US"
  }]'
```

## Step 4: Upload documents

Upload six PDF documents required for KYB verification. For sandbox testing,
create a minimal dummy PDF:

```shell theme={null}
printf '%%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f \n0000000009 00000 n \n0000000058 00000 n \n0000000115 00000 n \ntrailer<</Size 4/Root 1 0 R>>\nstartxref\n190\n%%%%EOF' > /tmp/dummy.pdf
```

Upload each document. Save the `documentId` from each response because you need
them to link documents back to their sections.

```shell theme={null}
# Business formation document
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=formation.pdf \
  -F datumName=businessFormationDocuments -F issuedCountry=US

# Financial statements
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=financials.pdf \
  -F datumName=financialStatements -F issuedCountry=US

# Proof of address
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=address.pdf \
  -F datumName=physicalAddressProofOfAddress -F issuedCountry=US

# Bank statement
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=bank.pdf \
  -F datumName=bankBrokerageCryptoStatement -F issuedCountry=US

# Ownership chart
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=ownership.pdf \
  -F datumName=ownershipChart -F issuedCountry=US
```

### 4.1. Upload the control person's government ID

The control person's government ID requires a `refId` and `documentType`. First,
retrieve the `refId`:

```shell theme={null}
curl --request GET \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/individualWithSignificantControlPersons \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

Find the `refId` value in `data.data[0].refId`, then upload the document:

```shell theme={null}
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/documents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  -F fileContent=@/tmp/dummy.pdf -F fileName=govid.pdf \
  -F datumName=controllerGovernmentId -F issuedCountry=US \
  -F refId={refId} -F documentType=passport
```

### 4.2. Re-save sections with document references

After uploading, link the documents back to their sections by re-saving the
section with the `documentId` values. For example, re-save
`businessRegistrationDetails` with the formation document:

```shell theme={null}
curl --request PUT \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/sections/businessRegistrationDetails \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "businessName": "My Company ABC1",
    "businessNameDifferent": false,
    "registrationNumber": "00-0000000",
    "taxId": "00-0000000",
    "countryOfFormation": "US",
    "businessStateOfRegistrationOfFormation": "NY",
    "dateOfFormation": "2010-01-01",
    "businessFormationDocuments": [{ "documentId": "YOUR_DOC_ID" }]
  }'
```

Repeat for these sections, adding the relevant `documentId` arrays:

* `physicalBusinessAddress`: add `physicalAddressProofOfAddress`
* `intendedUseOfAccount`: add `bankBrokerageCryptoStatement` and
  `financialStatements`
* `beneficialOwnersDetails`: add `ownershipChart`

## Step 5: Submit the application

Verify that all sections show a `complete` status:

```shell theme={null}
curl --request GET \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId} \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

When all sections are complete, submit the application:

```shell theme={null}
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/{applicationId}/submit \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header "X-Idempotency-Key: $(uuidgen)" \
  --data '{
    "endUserIpAddress": "203.0.113.1",
    "endUserAgreesToTermsOfService": true
  }'
```

<Note>
  In sandbox, the application is auto-approved almost immediately. In production,
  KYB verification takes time and may result in rejection.
</Note>

## Step 6: Retrieve your account

After the application is approved, retrieve the account using the
`clientEntityId` from step 1:

```shell theme={null}
curl --request GET \
  --url "https://api-sandbox.circle.com/v1/accounts?clientEntityId={clientEntityId}" \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

The response includes your active stablecoin account:

```json theme={null}
{
  "data": [
    {
      "accountId": "1017407114",
      "clientEntityId": "992063fe-d52f-3b1e-ab2d-637dd0b0f36e",
      "type": "client",
      "status": "active",
      "description": "Digital Asset Account External Entity Wallet",
      "balances": []
    }
  ]
}
```

Your `accountId` is now ready for deposits, withdrawals, and transfers. See
[Wire deposits and withdrawals](/digital-asset-accounts/howtos/wire-deposits-and-withdrawals)
to fund your account.

## Common issues

| Problem                          | Solution                                                                 |
| :------------------------------- | :----------------------------------------------------------------------- |
| `500` when creating client       | The company name was already used. Use a different `clientName`.         |
| `422` on intended use of account | Verify that enum values are exact matches.                               |
| Section stuck on `incomplete`    | Confirm that `taxId` is set in `businessRegistrationDetails`.            |
| `400` on submit                  | A section is not complete, or the `X-Idempotency-Key` header is missing. |
| `422` on government ID upload    | Add `documentType=passport` to the upload request.                       |
