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

# Connect Wallet (SIWE) — GET/POST /api/merchant/wallet/connect

> GET /api/merchant/wallet/connect — issues a SIWE nonce challenge; POST /api/merchant/wallet/connect — verifies a signature and links an external wallet to the merchant account.

The wallet connect endpoint links an external wallet (MetaMask, WalletConnect, or Coinbase) to an already-authenticated merchant using a two-step Sign-In With Ethereum (SIWE) flow. First `GET` a nonce challenge, have the user sign the returned message with their wallet, then `POST` the signature back. Ownership is proven by the signature — this route never stores a private key.

## Endpoint

```
GET  https://flarehq.xyz/api/merchant/wallet/connect?address={walletAddress}
POST https://flarehq.xyz/api/merchant/wallet/connect
```

## Request

### Headers

| Header | Value |
| - | - |
| `Cookie` | `merchant_token=...` — required |
| `x-api-key` | `arc_live_...` — accepted as an alternative |

Both verbs authenticate via the merchant — either the `merchant_token` cookie (browser dashboard) or the merchant's `x-api-key` header (API-style calls) is accepted.

### Step 1 — GET (issue challenge)

<ParamField body="address" type="string" required>
  Query parameter — the external wallet address the merchant wants to link (e.g. `0xAbCd...`). Must be an EVM address.
</ParamField>

The response returns a SIWE-formatted message and sets a short-lived `wallet_connect_nonce` cookie (HTTP-only, **5 minutes**). The message looks like:

```
https://flarehq.xyz wants you to sign in with your Ethereum account:
0xAbCd...

Link this wallet to your FlareHQ merchant account.

URI: https://flarehq.xyz
Version: 1
Nonce: 5f1e0c8b7d99a2b3c4d5e6f7a8b9c0d1e
Issued At: 2026-08-16T10:00:00.000Z
```

### Step 2 — POST (verify signature)

<ParamField body="address" type="string" required>
  The wallet address being linked — must match the address used in step 1.
</ParamField>

<ParamField body="message" type="string" required>
  The exact SIWE message returned by step 1, signed by the wallet.
</ParamField>

<ParamField body="signature" type="string" required>
  The signature produced by the wallet when signing the message.
</ParamField>

<ParamField body="walletKind" type="string" required>
  Wallet type. Must be one of `"METAMASK"`, `"WALLETCONNECT"`, or `"COINBASE"`.
</ParamField>

## Response

### GET — Success

<ResponseField name="success" type="boolean">
  `true` when the challenge is issued.
</ResponseField>

<ResponseField name="message" type="string">
  The SIWE message the merchant's wallet must sign. Contains the challenge nonce.
</ResponseField>

### POST — Success

<ResponseField name="success" type="boolean">
  `true` when the signature verifies and the wallet is linked.
</ResponseField>

<ResponseField name="wallet" type="object">
  The newly linked wallet.

  <Expandable title="wallet fields">
    <ResponseField name="wallet.walletProvider" type="string">
      The `walletKind` passed in the request, e.g. `"METAMASK"`.
    </ResponseField>

    <ResponseField name="wallet.walletAddress" type="string">
      The linked external wallet address.
    </ResponseField>
  </Expandable>
</ResponseField>

## Examples

<CodeGroup>
  ```bash cURL — Step 1 theme={null}
  curl "https://flarehq.xyz/api/merchant/wallet/connect?address=0xAbCd1234ef5678901234AbCd1234ef5678901234" \
    -b cookies.txt \
    -c cookies.txt
  ```

  ```bash cURL — Step 2 theme={null}
  curl -X POST https://flarehq.xyz/api/merchant/wallet/connect \
    -b cookies.txt \
    -H "Content-Type: application/json" \
    -d '{
      "address": "0xAbCd1234ef5678901234AbCd1234ef5678901234",
      "message": "https://flarehq.xyz wants you to sign in with your Ethereum account:\n0xAbCd...\n\nLink this wallet to your FlareHQ merchant account.\n\nURI: https://flarehq.xyz\nVersion: 1\nNonce: 5f1e0c8b...\nIssued At: 2026-08-16T10:00:00.000Z",
      "signature": "0x...",
      "walletKind": "METAMASK"
    }'
  ```

  ```js Node.js (fetch) theme={null}
  // Step 1 — get the challenge
  const challenge = await fetch(
    'https://flarehq.xyz/api/merchant/wallet/connect?address=0xAbCd1234ef5678901234AbCd1234ef5678901234',
    { credentials: 'include' }
  ).then((r) => r.json());

  // Step 2 — after the user signs `challenge.message` in their wallet
  const res = await fetch('https://flarehq.xyz/api/merchant/wallet/connect', {
    method: 'POST',
    credentials: 'include',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      address: '0xAbCd1234ef5678901234AbCd1234ef5678901234',
      message: challenge.message,
      signature: signedMessage,
      walletKind: 'METAMASK',
    }),
  });

  const { success, wallet } = await res.json();
  ```
</CodeGroup>

### GET — Success Response

```json theme={null}
{
  "success": true,
  "message": "https://flarehq.xyz wants you to sign in with your Ethereum account:\n0xAbCd1234ef5678901234AbCd1234ef5678901234\n\nLink this wallet to your FlareHQ merchant account.\n\nURI: https://flarehq.xyz\nVersion: 1\nNonce: 5f1e0c8b7d99a2b3c4d5e6f7a8b9c0d1e\nIssued At: 2026-08-16T10:00:00.000Z"
}
```

### POST — Success Response

```json theme={null}
{
  "success": true,
  "wallet": {
    "walletProvider": "METAMASK",
    "walletAddress": "0xAbCd1234ef5678901234AbCd1234ef5678901234"
  }
}
```

### Error Responses

```json theme={null}
{
  "success": false,
  "error": "Authentication required."
}
```

```json theme={null}
{
  "success": false,
  "error": "address query param required."
}
```

```json theme={null}
{
  "success": false,
  "error": "address, message, signature, and walletKind are required."
}
```

```json theme={null}
{
  "success": false,
  "error": "walletKind must be one of: METAMASK, WALLETCONNECT, COINBASE"
}
```

```json theme={null}
{
  "success": false,
  "error": "Missing or expired challenge — request a new one via GET first."
}
```

```json theme={null}
{
  "success": false,
  "error": "Signature verification failed."
}
```

## Notes

<Note>
  The nonce challenge expires after **5 minutes**. If the POST arrives after expiry — or the nonce cookie is missing because the flow was skipped — the request fails with `"Missing or expired challenge"` and you must start over from the GET step.
</Note>

<Warning>
  Linking an external wallet makes your **payout wallet** external. Settlement funds then land in a wallet you hold the keys to directly, and the [withdraw endpoint](/api-reference/merchant/withdraw) — which only works for Circle-managed wallets — becomes unavailable.
</Warning>
