# Prove and Link an Address

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

Send an address's two signatures: Aurea checks both, keeps the address and links it to the user's bank ramp customer.

## Overview

- **`signature`** signs the challenge's `message`: an account's EIP-191 signature, or a smart account's ERC-1271 signature, which Aurea checks on the chain (`503` `BANK_RAMP_ADDRESS_UNVERIFIED` when the chain's node does not answer). A wrong one answers `400` `BANK_RAMP_ADDRESS_SIGNATURE_INVALID` with `details.signature` `challenge`, `details.reason` and `details.attemptsLeft`: five wrong ones spend the challenge.
- **`linkSignature`** signs `linkMessage` the same ways — or is `0x` for a smart account that signs the bank ramp's message on chain (only an address with code may: `400` with `details.reason` `not_a_contract` otherwise). A wrong one answers `400` `BANK_RAMP_ADDRESS_SIGNATURE_INVALID` with `details.signature` `link`. Both are checked before anything reaches the bank ramp.
- **Answers:** `201` `linked`; `202` `pending` for `0x` — the bank ramp waits for the signature on chain, and [List Addresses](https://docs.aureahub.com/docs/bank-customer-addresses.md) reads it again; `200` when the customer had the address on that chain already.
- The challenge is spent once verified. A used, expired or spent one answers `409` `BANK_RAMP_ADDRESS_CHALLENGE_SPENT` (`details.reason` `used`, `expired` or `burnt`): ask for a new one. Another user's or an unknown challenge: `404` `BANK_RAMP_ADDRESS_CHALLENGE_NOT_FOUND`.
- The environment and chain are the challenge's; the standalone mode and the chain must still be on.
- While your tenant's [audit trail](https://docs.aureahub.com/docs/audit-events.md) is on, it records `bank_ramp_address.linked` (category `security`) — never the address or a signature.

## Endpoint

### `POST /v1/ramp/bank/customer/addresses/verify`

Authentication: bearer token required.

Checks an address's two signatures, keeps the address and links it at the bank ramp.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `challengeId` | string | yes | The challenge's `challengeId` |
| `signature` | string | yes | The address's signature of `message` (1 to 4000 characters) |
| `linkSignature` | string | yes | Its signature of `linkMessage`, or `0x` for a smart account that signs on chain (2 to 4000 characters) |

**Responses**

`201` Linked

```json
{
  "addressId": "6c2e8a4f-0b1d-4f3a-9e7c-5d2b8f1a6c39",
  "address": "0xC0207704CaEB9342cf491Ad4a177F43592df65a7",
  "network": "gnosis",
  "environment": "sandbox",
  "proof": "eip191",
  "linkSignature": "eoa",
  "status": "linked",
  "failureCode": null,
  "verifiedAt": "2026-10-14T10:02:00.000Z",
  "linkedAt": "2026-10-14T10:02:01.000Z"
}
```

`202` Pending (on chain)

```json
{
  "addressId": "1e5b9d3f-7a2c-4c8e-b0d6-4f1a3c5e7b92",
  "address": "0x2F1b0dA7C3e95d4c8bB6a0E7F4d1C9a3b5E8f702",
  "network": "base",
  "environment": "sandbox",
  "proof": "erc1271",
  "linkSignature": "onchain",
  "status": "pending",
  "failureCode": null,
  "verifiedAt": "2026-10-14T10:04:00.000Z",
  "linkedAt": null
}
```

`400` Wrong signature

```json
{
  "statusCode": 400,
  "error": "BadRequestError",
  "message": "The signature is not the address's over the challenge.",
  "details": {
    "code": "BANK_RAMP_ADDRESS_SIGNATURE_INVALID",
    "signature": "challenge",
    "reason": "wrong_signer",
    "attemptsLeft": 4
  }
}
```

`409` Challenge spent

```json
{
  "statusCode": 409,
  "error": "ConflictError",
  "message": "This challenge can no longer be signed: ask for a new one.",
  "details": { "code": "BANK_RAMP_ADDRESS_CHALLENGE_SPENT", "reason": "expired" }
}
```

`proof`: how the address proved it is the user's — `eip191` (an account) or `erc1271` (a smart account). `linkSignature`: how it signed the bank ramp's message — `eoa`, `erc1271` or `onchain`.

---

Web version: https://docs.aureahub.com/#bank-customer-address-verify
