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

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# How-to: Handle requests for information

> Respond to compliance team RFIs by updating data, uploading and saving documents, and resubmitting applications

Resolve compliance team requests so your application can proceed to approval.
List RFI bundles to see what's needed, update the requested fields or documents,
respond with comments, and resubmit the application.

<Note>
  The End User Onboarding API base URL is `https://api-sandbox.circle.com` for
  sandbox and `https://api.circle.com` for production. All requests require a
  Bearer token obtained via Circle key exchange in the `Authorization` header. All
  `POST` requests require an `X-Idempotency-Key` header with a client-generated
  UUID v4.
</Note>

## Prerequisites

Before you begin, ensure that you've:

* Obtained an API key for the End User Onboarding API from the
  [Circle Console](https://console.circle.com).
* Confirmed your application is in `PENDING_CUSTOMER_INFORMATION` status. See
  [Application types and states](/end-user-onboarding/references/application-states)
  for the full lifecycle.

<Note>
  In the sandbox, Know Your Business (KYB) applications auto-approve on
  submission. To get an application into review so an RFI can be issued, submit it
  with a reserved business name. See
  [Magic numbers for testing](/end-user-onboarding/references/testing-magic-numbers).
</Note>

## Steps

### Step 1. List RFI bundles

When an application moves to `PENDING_CUSTOMER_INFORMATION`, the `pendingRfis`
array on the application response contains the bundle IDs. List all bundles:

```bash theme={null}
curl --request GET \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/${APPLICATION_ID}/rfis \
  --header "Authorization: Bearer ${YOUR_API_KEY}"
```

**Example response:**

```json theme={null}
{
  "data": {
    "bundles": [
      {
        "bundleId": "660e8400-e29b-41d4-a716-446655440010",
        "status": "PUBLISHED",
        "createdAt": "2026-03-26T10:00:00Z",
        "rfis": [
          {
            "rfiId": "770e8400-e29b-41d4-a716-446655440011",
            "section": "beneficialOwnerPersons",
            "field": "passport_document",
            "type": "UPDATE_FIELD",
            "status": "PENDING",
            "systemComment": "Document is illegible. Please upload a clearer copy.",
            "refId": "3de289ef-7947-457d-bbcd-a4fc8dc3b1aa",
            "createdAt": "2026-03-26T10:00:00Z"
          },
          {
            "rfiId": "880e8400-e29b-41d4-a716-446655440012",
            "section": "businessRegistrationDetails",
            "field": "businessWebsite",
            "type": "UPDATE_FIELD",
            "status": "PENDING",
            "systemComment": "Please provide your company website.",
            "refId": null,
            "createdAt": "2026-03-26T10:01:00Z"
          }
        ]
      }
    ]
  }
}
```

Each RFI identifies the `section` and `field` that needs attention. The
`systemComment` explains what the compliance team requires.

RFI types and statuses:

| Field | Values |
| - | - |
| RFI `type` | `UPDATE_FIELD` and `NEW_FIELD`: respond with the field value. `NOTE`: respond with a comment only. |
| RFI `status` | `PENDING` until you respond, then `RESPONDED`. |
| Bundle `status` | `PUBLISHED` while it waits for your response, then `RESPONDED` once every RFI in the bundle has been responded to, then `SUBMITTED` after you resubmit. |

Resubmitting the application returns `409` while any RFI is still `PENDING`.

<Note>
  Array sections and `refId`: Some sections, such as `beneficialOwnerPersons`,
  `beneficialOwnerEntity`, or `trustRelatedPersons`, can contain multiple entries
  (for example, multiple beneficial owners). When an RFI targets a field in one of
  these sections, the response includes a `refId` identifying which specific
  entity the RFI is for. `refId` is `null` for RFIs on single-instance sections
  (such as `businessRegistrationDetails`) and for `NOTE` RFIs. Use `refId` when
  responding. See [Step 3](#step-3-update-the-requested-data).
</Note>

### Step 2. View RFI detail and comments

Retrieve the full detail for a specific RFI, including any prior comments:

```bash theme={null}
curl --request GET \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/${APPLICATION_ID}/rfis/${RFI_ID} \
  --header "Authorization: Bearer ${YOUR_API_KEY}"
```

### Step 3. Update the requested data

For RFIs with type `UPDATE_FIELD` or `NEW_FIELD`, submit the corrected field
data directly to the RFI. The request body shape depends on whether the RFI
targets a single-instance section or an array section.

Single-instance section (`refId` is `null`): submit a flat JSON object with the
field name as the key:

```bash theme={null}
curl --request PATCH \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/${APPLICATION_ID}/rfis/${RFI_ID} \
  --header "Authorization: Bearer ${YOUR_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
    "businessWebsite": "https://example.com"
  }'
```

Array section (`refId` is present): submit a single-element JSON array
containing the `refId` from the RFI response alongside the updated field. This
tells the API exactly which entity to update:

```bash theme={null}
curl --request PATCH \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/${APPLICATION_ID}/rfis/${RFI_ID} \
  --header "Authorization: Bearer ${YOUR_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '[{
    "refId": "3de289ef-7947-457d-bbcd-a4fc8dc3b1aa",
    "trustRelatedPersonLastName": "Smith"
  }]'
```

The `refId` in the body must match the `refId` on the RFI. The API rejects
mismatches. Replace the field name with the `field` value from the RFI.

The API validates the submitted value against the application schema and marks
the RFI as responded.

When the RFI's `field` is a document field, such as `passport_document`, upload
a new file first. Then save the document field with the `documentId` from the
upload response. This applies to any RFI type. Uploading alone does not respond
to the RFI. When the RFI has a `refId`, include it in the upload request to
associate the file with the correct entity. See
[Upload documents](/end-user-onboarding/howtos/upload-documents) for the upload
workflow.

You can also respond by saving the field with a
[section save](/end-user-onboarding/howtos/create-and-populate-applications#step-4-save-section-data)
(`PUT /v1/onboarding/partner/applications/{applicationId}/sections/{sectionName}`)
or a
[bulk save](/end-user-onboarding/howtos/create-and-populate-applications#step-5-bulk-save-optional)
(`PATCH /v1/onboarding/partner/applications/{applicationId}/data`). You don't
need to pass the `rfiId`. The API matches the RFI by section, field, and
`refId`.

<Warning>
  An RFI is marked as responded only when the saved value changes. If the current
  value is correct, reply with a comment instead. See
  [Step 4](#step-4-respond-with-a-comment).
</Warning>

### Step 4. Respond with a comment

Add a comment to an RFI to communicate with the compliance team:

```bash theme={null}
curl --request POST \
  --url https://api-sandbox.circle.com/v1/onboarding/partner/applications/${APPLICATION_ID}/rfis/${RFI_ID}/comments \
  --header "Authorization: Bearer ${YOUR_API_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'X-Idempotency-Key: ${IDEMPOTENCY_KEY}' \
  --data '{
    "content": "Updated the field as requested."
  }'
```

### Step 5. Resubmit the application

After you address all open RFIs, resubmit the application so it moves back to
`SUBMITTED` for another round of review. For Stablecoin KYB, collect device risk
signals in the browser first. See
[Collect device risk signals](/end-user-onboarding/howtos/collect-device-risk-signals).
Then resubmit:

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

This is the same endpoint used during initial submission. For details on
optional fields such as `certificationIds`, see
[Submit and track applications](/end-user-onboarding/howtos/submit-and-track-applications#step-2-submit-the-application).
Device-check outcomes use the same codes as initial submit
([`181110`](/api-reference/end-user-onboarding/error-codes),
[`181111`](/api-reference/end-user-onboarding/error-codes),
[`181108`](/api-reference/end-user-onboarding/error-codes)).

## See also

* [Collect device risk signals](/end-user-onboarding/howtos/collect-device-risk-signals)
* [Submit and track applications](/end-user-onboarding/howtos/submit-and-track-applications)
* [Application types and states](/end-user-onboarding/references/application-states)
* [Upload documents](/end-user-onboarding/howtos/upload-documents)
* [Magic numbers for testing](/end-user-onboarding/references/testing-magic-numbers)
