# Complete Hosted Onboarding

> Coming soon, upon request — this feature is turned on for your tenant by the Aurea team. [Contact us](https://www.aureahub.com/contact)

Hand Aurea the `code` and `state` the bank ramp sent the user back with: the user becomes your tenant's customer.

## Overview

- **The state** must be Aurea's, unchanged, unexpired, unused and this user's — another user of your tenant cannot use it. Otherwise `400` `BANK_RAMP_AUTHORIZATION_INVALID`, and nothing reaches the bank ramp: start again. The environment is the state's.
- Aurea exchanges the code with the PKCE verifier it kept; the bank ramp refusing it (unknown, used, expired) also answers `400` `BANK_RAMP_AUTHORIZATION_INVALID`, and the request is spent.
- Aurea reads the user's profile with the user's own authorization and makes it the user's customer: `201`; `200` when it already was. `409` `BANK_RAMP_AUTHORIZATION_NO_PROFILE` when the user has no profile at the bank ramp yet (they finish onboarding there and authorize again); `409` `BANK_RAMP_CUSTOMER_EXISTS` when the user is another customer in that environment, or the profile is another user's.
- **Aurea keeps the authorization**, encrypted, to read the customer for you: there are no notifications in this mode, so read its state with [Sync the Customer](https://docs.aureahub.com/docs/bank-customer-sync.md). [Hosted Authorization](https://docs.aureahub.com/docs/bank-customer-authorization.md) says whether it is kept.
- While your tenant's [audit trail](https://docs.aureahub.com/docs/audit-events.md) is on, it records `bank_ramp_customer.authorized` (category `access`) — never a code or a token.
- The KYC on and the `hosted_oauth` strategy, as in [Start Hosted Onboarding](https://docs.aureahub.com/docs/bank-customer-authorize.md).

## Endpoint

### `POST /v1/ramp/bank/customer/authorize/complete`

Authentication: bearer token required.

Finishes the user's hosted onboarding and answers the customer.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | The `state` the bank ramp sent back, 1 to 1024 characters |
| `code` | string | yes | The `code` the bank ramp sent back, 1 to 512 characters |

**Responses**

`201` Customer

```json
{
  "environment": "sandbox",
  "customer": {
    "customerId": "5a9d3c71-2e4f-4b86-9c0a-7d1e3f5b8a24",
    "profileId": "1f0e8c2a-9b7d-11ef-8a3c-0242ac120002",
    "kind": "personal",
    "environment": "sandbox",
    "registered": true,
    "state": "approved",
    "sections": { "details": "approved", "form": "approved", "verifications": [] },
    "closedReason": null,
    "errorFields": [],
    "createdAt": "2026-10-14T10:12:00.000Z",
    "updatedAt": "2026-10-14T10:12:00.000Z"
  },
  "verification": { "state": "approved", "nextStep": "approved", "missing": [], "kycStrategy": "hosted_oauth" }
}
```

`400` Start again

```json
{
  "statusCode": 400,
  "error": "BankRampProviderError",
  "message": "The bank ramp refused the authorization: start it again",
  "details": { "code": "BANK_RAMP_AUTHORIZATION_INVALID" }
}
```

`409` No profile yet

```json
{
  "statusCode": 409,
  "error": "ConflictError",
  "message": "The user has no profile at the bank ramp yet: finish onboarding there and authorize again.",
  "details": { "code": "BANK_RAMP_AUTHORIZATION_NO_PROFILE", "environment": "sandbox" }
}
```

`409` Another customer

```json
{
  "statusCode": 409,
  "error": "ConflictError",
  "message": "This user is already another customer of the bank ramp in sandbox.",
  "details": { "code": "BANK_RAMP_CUSTOMER_EXISTS", "environment": "sandbox" }
}
```

---

Web version: https://docs.aureahub.com/#bank-customer-authorize-complete
