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

# Send winners

If you'd rather call us than publish a URL, switch the campaign's **Winners** section to push in the partner portal, and your backend posts each drawing's winners before its cutoff. Posting to a pull campaign returns `409 pull_campaign`.

## The loop

Drawings are created about two days ahead, so your backend can run this on a schedule, once your draw has happened:

1. `GET /api/v1/campaigns/{slug}/drawings?status=open`. Open drawings come soonest first, so the first one is the next cutoff. Take its `id` and `winnersExpected`.
2. Pick that many winners by your own rules.
3. `POST` them to that drawing, below. Keep the `id` with your own record of the draw, so a retry posts to the same drawing.
4. Before the next draw, the next open drawing is first in the list.

If the post fails or times out, send the same list again. A retry is always safe.

```http theme={null}
POST /api/v1/campaigns/{slug}/drawings/{id}/winners
Content-Type: application/json
```

```json theme={null}
{
  "winners": [
    "user-8231",
    { "winner": "user-4417", "displayName": "Ada", "avatarUrl": "https://…/ada.png" },
    "user-0092"
  ]
}
```

Send exactly as many winners as the drawing's `winnersExpected`. Each is either:

* a string, the winner's id, or
* an object with `winner` plus an optional `displayName` (up to 40 characters) and `avatarUrl` (https, up to 2,048 characters), shown on the campaign page.

The same winner can't appear twice in one list. **Order matters:** each winner's position is part of how their prize is decided.

The response is the drawing, with the winners filled in: `201` the first time, `200` after that.

## Replacing and retrying

| When | Sending again |
| - | - |
| Before the cutoff | Replaces the list. |
| After the cutoff, same list | Returns `200`. A retry is always safe. |
| After the cutoff, different list | Returns `409 locked`. |

Names and avatars aren't locked. Resend the same winners with new ones to update them at any time, even after the draw.

## No winners by the cutoff

A drawing with no winners at its cutoff is flagged and waits. Extend its cutoff in the partner portal, then send the list.

## Winner ids

<Warning>
  Winner ids are public in each draw's proof. Use an id that can't be guessed or linked back to a person: an HMAC of your user id with a secret key, or a random id you store. A plain hash of a sequential or public user id can be reversed by trying ids. Keep the key fixed for the life of the campaign, and never use emails or usernames.
</Warning>

## Errors

| Status | Code | When |
| - | - | - |
| 400 | `bad_request` | Not JSON, the wrong number of winners, a repeated winner, or a bad name or avatar. |
| 404 | `not_found` | No such campaign or drawing under your account. |
| 409 | `locked` | The cutoff has passed and this list differs from the locked one. |
| 409 | `pull_campaign` | Prizerail fetches this campaign's winners from your URL. |
| 409 | `campaign_ended` | The campaign has ended. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.