# Register an affiliate

`POST /api/market/affiliates/register`

Optional, kept for compatibility: any address is an affiliate and is paid without registering. It still verifies as before: a BIP-322 signature by the payout address of `raresats.net affiliate <address> <unix seconds>`, at most 10 minutes old, used once. The registering wallet's addresses are kept with it and only ever narrow what the affiliate is paid: a purchase by any of them is a self-referral (`affiliate_wallet`). Registering again adds the new wallet's addresses.

#### Request body

`content-type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `address` | string | yes | The payout address: Taproot, native SegWit or nested SegWit (it must sign BIP-322). |
| `message` | string | yes | `raresats.net affiliate <address> <unix seconds>`, at most 10 minutes old (2 minutes ahead at most), usable once. |
| `signature` | string | yes | The BIP-322 signature of `message` by `address` (base64), as wallets' signMessage makes it. |
| `wallet_addresses` | array of string | no | Optional: the registering wallet's other addresses (payment and ordinals). A purchase by any of them never pays this affiliate. (0-4 items) |

#### Example request

```bash title="cURL"
curl -X POST 'https://raresats.net/api/market/affiliates/register' \
  -H 'content-type: application/json' \
  -d '{
  "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
  "message": "raresats.net affiliate bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh 1790949000",
  "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E",
  "wallet_addresses": ["37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"]
}'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/market/affiliates/register', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "message": "raresats.net affiliate bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh 1790949000",
    "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E",
    "wallet_addresses": ["37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"]
  })
});
const data = await response.json();
```
```python title="Python"
import requests

data = requests.post("https://raresats.net/api/market/affiliates/register", json={
    "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "message": "raresats.net affiliate bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh 1790949000",
    "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E",
    "wallet_addresses": ["37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"]
}).json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `affiliate` | object |  |
| `affiliate.address` | string | The registered payout address, normalized. |
| `affiliate.registered_at` | integer | When it first registered (unix seconds). |
| `affiliate.wallet_addresses` | array of string | Every address recorded for it: the payout and the registering wallets' addresses. |

```json title="Response"
{
  "affiliate": {
    "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "registered_at": 1790949000,
    "wallet_addresses": [
      "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
      "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh"
    ]
  }
}
```

#### Errors

`{error, code}`; see [Errors](https://raresats.net/docs/errors.md) for every code.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `bad_address` | An address is not a mainnet address (or not one at all). |
| 400 | `bad_json` | The body is not valid JSON. |
| 400 | `bad_message` | The cancel message is not `raresats.net cancel <ids> <unix seconds>` or names other listings than `ids`; or the registration message is not `raresats.net affiliate <address> <unix seconds>` for `address`. |
| 400 | `bad_request` | The body is not a JSON object, or the engine refused a malformed request (e.g. a purchase submitted without its signed setup PSBT). |
| 400, 422 | `bad_signature` | 400: `signature` is missing or too long. 422: a signature does not verify (cancel or registration message, listing or purchase input). |
| 400 | `bad_wallet_addresses` | `wallet_addresses` is not a list of at most 4 mainnet addresses. |
| 403 | `cross_origin` | A POST from a browser on another site (a foreign `Origin`, or `sec-fetch-site: cross-site`). Server-side clients send no `Origin` and are not affected. |
| 405 | `method_not_allowed` | Wrong method for the route; the `allow` header lists the right ones. |
| 409 | `replayed` | That cancel or registration message was used already. |
| 413 | `too_large` | The body is over 256 KiB. |
| 415 | `not_json` | A POST without `content-type: application/json`. |
| 422 | `future_message` | The cancel or registration message is dated more than 2 minutes ahead: check the clock. |
| 422 | `legacy_address` | A legacy (P2PKH, `1…`) address: use Taproot or SegWit. |
| 422 | `stale_message` | The cancel or registration message is more than 10 minutes old: sign a new one. |
| 422 | `unsupported_address` | An address type the marketplace does not trade (only Taproot, native SegWit and nested SegWit). |
| 429 | `rate_limited` | Over 30 POSTs a minute from your IPv4 address or IPv6 /64 (in chat, counted per IPv4 address or IPv6 /64: 30 writes and 20 login nonces a minute, 20 sign-ins and 10 display-name changes an hour; one message every 3 s and 20 a minute per address); wait `retry-after` seconds. With the AI moderation on, at most 6 messages and names a minute are checked per address and per IPv4 address or IPv6 /48. |
| 503 | `engine_unavailable` | The trade engine is not available. |

```json title="Error (400)"
{
  "error": "the signature does not verify for that address and message",
  "code": "bad_signature"
}
```

**Optional, kept for compatibility.** Any address is an affiliate without registering: referrals to it are paid whether or not it ever registered. This endpoint still works for clients written when it was required, and it verifies exactly as before; registering changes only one thing, and only in the affiliate's disfavour: the wallet addresses it records count as the affiliate's own, so a purchase by any of them is a self-referral (`affiliate_wallet`) and pays nothing.

To register, sign this message with the payout address (BIP-322, as wallets' `signMessage` makes it) and send it within 10 minutes:

```text
raresats.net affiliate <address> <unix seconds>
```

A signed message is usable once. `wallet_addresses` lists the registering wallet's other addresses (its payment and ordinals addresses). Registering again from another wallet adds that wallet's addresses. The payout address must be Taproot, native SegWit or nested SegWit, which is what BIP-322 signs with. How the programme works: [Affiliates](https://raresats.net/docs/guide-affiliates.md).
