### Redeem a card onto a subscriber

`POST /api/v1/cards/redeem`

Spends a card and applies its effect to the named subscriber. Two authority checks run, both derived from your credential and neither from the body: the card must be in your subtree, and the subscriber must be one you may write to. Both denials are 404s identical to "no such card" and "no such subscriber".

- Authentication: manager session (JWT) or API token
- Permission: `prm_cards_verify` (Verify / redeem cards)
- Risk: write
- Rate limit bucket: `card_redeem`
- Idempotent on `request_id`: retrying with the same id returns the original result

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `code` | body | string | yes | The plaintext card code. |
| `user_id` | body | integer | yes | The subscriber to credit. |
| `request_id` | body | string | yes | Idempotency key. |

#### Request

```json
{
  "code": "K7P4M2Q9XD",
  "user_id": 4711,
  "request_id": "3a1d0c77-8b52-4e19-9d64-1f7e2c5a9b30"
}
```

#### Response — 200 OK

```json
{
  "data": {
    "card_id": 90211,
    "mode": "refill_balance",
    "user_id": 4711,
    "effect_applied": { "type": "add_balance", "amount": 150.00 },
    "new_balance": 400.00
  }
}
```

#### Errors

| Code | Status | When |
| --- | --- | --- |
| `ERR_VALIDATION` | 400 | code, user_id or request_id missing, or a reserved or over-long request_id |
| `ERR_NOT_FOUND` | 404 | unknown code, a card outside your subtree, or a subscriber you may not write to |
| `ERR_CONFLICT` | 409 | the card is already redeemed, or the request_id belongs to a redemption of a different card |
| `ERR_CONFLICT` | 410 | the card has been revoked or has expired |

#### Note

A replay returns 200 with the same card_id, mode and effect_applied, and NO replay flag — but new_balance is ABSENT, because the replay path returns the stored effect without re-reading the wallet. A missing new_balance is not a failure and is not a reason to retry. Read the balance off the subscriber record if you need it.

