# Ask for an Address Challenge

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

Get the two messages an address outside Aurea signs to be proven to Aurea and linked to the user's bank ramp customer.

## Overview

An address outside Aurea is proven twice: to Aurea, by signing `message`, and to the bank ramp, by signing `linkMessage`. [Prove and Link an Address](https://docs.aureahub.com/docs/bank-customer-address-verify.md) takes both signatures.

- **Your tenant's standalone mode must be on** in the environment (`403` `BANK_RAMP_MODE_OFF`), `network` one it offers (`400` `BANK_RAMP_PAIR_UNAVAILABLE`), and the user a confirmed customer (`404` `BANK_RAMP_CUSTOMER_NOT_FOUND`).
- `address`: an EVM address; mixed case only with a valid checksum, never the zero address (`400` `BANK_RAMP_ADDRESS_INVALID`). The answer carries it with its checksum.
- `message` is Aurea's challenge: it names the address, the environment, your tenant, the user, a random nonce and its times. `linkMessage` is the bank ramp's fixed message. **Sign both exactly as returned**, line breaks included — with `personal_sign`, or with a smart account's own signature (ERC-1271).
- A challenge lasts 10 minutes (`expiresAt`). A user holds at most 5 open challenges: beyond that, `409` `BANK_RAMP_ADDRESS_CHALLENGE_LIMIT`.

## Endpoint

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

Authentication: bearer token required.

Issues the messages that prove and link one address of the user on a chain.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `address` | string | yes | The EVM address, up to 100 characters |
| `network` | string | yes | `ethereum`, `gnosis`, `polygon`, `arbitrum` or `base` |
| `isTestnet` | boolean | no | `true` for the sandbox; `false` or omitted for production |

**Responses**

`201` Created

```json
{
  "challengeId": "3d7f1b9e-5a2c-4e6d-8b0f-1c3e5a7d9b42",
  "address": "0xC0207704CaEB9342cf491Ad4a177F43592df65a7",
  "network": "gnosis",
  "environment": "sandbox",
  "message": "Aurea asks you to prove that you control this address, to use it with the bank ramp.\nSigning this message moves no funds and costs nothing.\n\nAddress: 0xC0207704CaEB9342cf491Ad4a177F43592df65a7\nAddress type: EVM\nEnvironment: sandbox\nTenant: 3f0e1c2a-8b7d-4c6e-9a5f-1d2c3b4a5e6f\nUser: 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d\nNonce: 8f3c2a9d4e1b7f6a0c5d2e8b3a9f1c7d4e6b0a2f8c3d5e9a1b7c4f0d6e2a8b3c\nIssued at: 2026-10-14T10:00:00.000Z\nExpires at: 2026-10-14T10:10:00.000Z",
  "linkMessage": "I hereby declare that I am the address owner.",
  "expiresAt": "2026-10-14T10:10:00.000Z"
}
```

`409` Too many open

```json
{
  "statusCode": 409,
  "error": "ConflictError",
  "message": "A user has at most 5 open challenges: sign one or let it expire first",
  "details": { "code": "BANK_RAMP_ADDRESS_CHALLENGE_LIMIT", "limit": 5 }
}
```

`403` Standalone off

```json
{
  "statusCode": 403,
  "error": "ForbiddenError",
  "message": "The bank ramp's standalone mode is not switched on for this tenant in sandbox.",
  "details": { "code": "BANK_RAMP_MODE_OFF", "mode": "standalone", "environment": "sandbox" }
}
```

## Implementation

```javascript
// An account in the browser (ethers v6): both signatures with personal_sign
import { BrowserProvider } from 'ethers';

async function proveAndLink(token) {
  const signer = await new BrowserProvider(window.ethereum).getSigner();
  const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` };

  const challenge = await fetch('https://api.aureahub.com/v1/ramp/bank/customer/addresses/challenge', {
    method: 'POST', headers,
    body: JSON.stringify({ isTestnet: true, address: await signer.getAddress(), network: 'gnosis' })
  }).then((r) => r.json());

  const res = await fetch('https://api.aureahub.com/v1/ramp/bank/customer/addresses/verify', {
    method: 'POST', headers,
    body: JSON.stringify({
      challengeId: challenge.challengeId,
      signature: await signer.signMessage(challenge.message),
      linkSignature: await signer.signMessage(challenge.linkMessage)
    })
  });
  const address = await res.json();
  if (!res.ok) throw new Error(`${res.status} ${address.details?.code}`);
  return address; // status: linked (201), pending (202), or already linked (200)
}
```

---

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