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

# Onboard & Connect a Customer

> Run the platform happy path end to end — register a customer, connect their account with OAuth, verify their identity, and operate on their behalf.

This Quickstart is the "Build a platform" story made runnable. You'll register a customer programmatically, walk the OAuth grant to get a token scoped to *their* account, verify their identity with the sandbox KYC flow, and prove the connection by issuing a virtual card on their behalf — with the exact same API you use on your own account.

<Info>
  **Prerequisites**

  * A **Fluz account with a staging application** — Steps 1–2 of any quickstart, or see [Prepare your accounts](/get-started/prepare-accounts) and [API credentials](/get-started/api-credentials).
  * An **OAuth-configured app**: a `client_id`, `client_secret`, and registered `redirect_uri` — see [Create an OAuth App](/create-an-o-auth-app) and [Configure OAuth App](/configure-o-auth-app).
  * Requests go to the **sandbox** — no real money, no real PII. See [Staging vs. Live Environment](/concepts/environments).
</Info>

<Warning>
  **Registering users requires special permission.** The `registerUser` mutation is gated per application (`AUTH-0022` if not enabled) — contact your account manager to enable it. No registration access yet? Skip Step 1 and run the flow with any existing staging user.
</Warning>

## The full flow

<Steps>
  <Step title="Register the customer" icon="user-plus">
    Provision a complete user — account, balances, and referral capability — with `registerUser`, authenticated with **your application's** token.

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation RegisterUser(
            $firstName: String!
            $lastName: String!
            $phoneNumber: String!
            $regionCode: String!
            $emailAddress: String!
            $dateOfBirth: String!
          ) {
            registerUser(
              firstName: $firstName
              lastName: $lastName
              phoneNumber: $phoneNumber
              regionCode: $regionCode
              emailAddress: $emailAddress
              dateOfBirth: $dateOfBirth
            ) {
              success
              error { code message }
            }
          }
      ```

      ```json Variables theme={null}
          {
            "firstName": "Jane",
            "lastName": "Doe",
            "phoneNumber": "5551234567",
            "regionCode": "US",
            "emailAddress": "jane.doe@example.com",
            "dateOfBirth": "1990-05-15"
          }
      ```
    </CodeGroup>

    <Warning>
      This mutation returns errors **in the response data**, not as GraphQL errors — always check `success` and handle the `error` object. Common failures: `AUTH-0026` / `AUTH-0027` (phone or email already in use), `AUTH-0004` (invalid phone). Full list: [User Registration](/user-registration).
    </Warning>
  </Step>

  <Step title="Send the customer through the OAuth grant" icon="plug">
    The customer authorizes your app by visiting the hosted grant page. Build the URL with your OAuth settings and the scopes your integration needs:

    ```text Authorization URL theme={null}
        https://uni.staging.fluzapp.com/authorize
          ?response_type=code
          &client_id=<YOUR_OAUTH_CLIENT_ID>
          &redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>
          &scopes=CREATE_VIRTUALCARD%20REVEAL_VIRTUALCARD
          &state=<OPTIONAL_OPAQUE_VALUE>
    ```

    * `scopes` is **space-delimited** (URL-encoded as `%20`) and must be a subset of the scopes enabled on your app — unknown scopes are silently ignored.
    * `state` is echoed back unmodified — use it to correlate the redirect with your session.

    The customer sees the Fluz permissions screen, approves, and is redirected to your `redirect_uri` with `?code=...&state=...`. That `code` is single-use — capture it server-side.

    Full parameter reference: [Client-Facing OAuth Grant Flow](/client-facing-o-auth-grant-flow).
  </Step>

  <Step title="Exchange the code for the customer's token" icon="key">
    Trade the authorization code for the customer-scoped `accessToken` (plus a `refreshToken`). This call authenticates with **Basic auth**: base64 of `client_id:client_secret`.

    <CodeGroup>
      ```bash Exchange (cURL) theme={null}
          curl -X GET "https://uni.staging.fluzapp.com/token/exchange?code=<AUTH_CODE>&redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>" \
            -H "Authorization: Basic <base64 of CLIENT_ID:CLIENT_SECRET>"
      ```

      ```json Response (truncated) theme={null}
          {
            "accessToken": "eyJhbGciOi...",
            "accessTokenExpiresAt": "2026-07-13T21:05:30.673Z",
            "refreshToken": "8ec16c25951616150b0332a4a6d66547",
            "refreshTokenExpiresAt": "2026-08-13T20:55:30.738Z",
            "scope": ["CREATE_VIRTUALCARD", "REVEAL_VIRTUALCARD"],
            "user": { "id": "5070d5a1-d71a-4190-91b0-f116eec51771" }
          }
      ```
    </CodeGroup>

    The `redirect_uri` must match the grant step **exactly**. Store the `refreshToken` and rotate before `accessTokenExpiresAt` — see [Refresh an OAuth Access Token](/refresh-o-auth-access-token).

    <Tip>
      Onboarding many customers? Append your own identifier as `external_id` on the authorize URL to link Fluz accounts to records in your system — see [Managing External Reference IDs](/managing-external-reference-ids).
    </Tip>
  </Step>

  <Step title="Verify the customer's identity (KYC)" icon="id-card">
    Money movement requires a verified identity. Call `verifyUserInformation` **with the customer's token** — the token determines who gets verified. In staging, this test identity always returns `APPROVED`:

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation VerifyUserInformation($input: VerifyUserInformationInput!) {
            verifyUserInformation(input: $input) {
              status
              message
            }
          }
      ```

      ```json Variables (approved test identity) theme={null}
          {
            "input": {
              "firstName": "John",
              "lastName": "Smith",
              "streetLine1": "222333 Peachtree Place",
              "streetLine2": "",
              "city": "Atlanta",
              "state": "GA",
              "postalCode": "30318",
              "country": "United States",
              "dateOfBirth": "02/28/1975",
              "ssnLast4": "3333"
            }
          }
      ```
    </CodeGroup>

    <Warning>
      **Three-attempt limit:** a user can be submitted at most 3 times before returning `ERROR` — don't burn attempts on a user you need. Full sandbox outcomes: [Testing KYC Flows](/test-kyc-flows).
    </Warning>
  </Step>

  <Step title="Operate on their account — prove it" icon="credit-card">
    This is the payoff: run any Fluz operation with the **customer's token** and it executes against **their** account. `createVirtualCard` is `createVirtualCard` — no separate platform API.

    ```graphql theme={null}
        mutation {
          createVirtualCard(
            input: {
              idempotencyKey: "1b7de2f8-c0a9-4532-9881-3ab5857bbe15"
              offerId: "ed669305-5e43-40a0-9a25-7a15ed174628"
              spendLimit: 50.00
              lockCardNextUse: true
              cardNickname: "First card on a connected account"
            }
          ) {
            virtualCardId
            virtualCardLast4
            status
          }
        }
    ```

    An `ACTIVE` card back means the loop is closed: registered → connected → verified → operating. The customer becomes visible in your systems through the token; they never gained access to *your* account, and you hold only the scopes they granted.
  </Step>
</Steps>

## You're done 🎉

You've onboarded and connected a customer end to end. From here:

<CardGroup cols={2}>
  <Card title="Build a platform" icon="layout-grid" href="/build-a-platform">
    The full platform architecture — token paths, capabilities, and patterns.
  </Card>

  <Card title="Approvals & requests" icon="check-check" href="/features/approvals-and-requests">
    Let connected users request actions that owners approve.
  </Card>

  <Card title="External reference IDs" icon="link" href="/managing-external-reference-ids">
    Address customers by your own IDs instead of Fluz account IDs.
  </Card>

  <Card title="Business registration & KYB" icon="building-2" href="/business-registration">
    Onboard businesses, not just individuals.
  </Card>
</CardGroup>

<Note>
  **Want to learn more?** Contact us at [support@fluz.app](mailto:support@fluz.app) to speak with our experts or request a demo.
</Note>
