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

# Sponsor draw entries

> Record a fan's entry in a sponsor's draw, and pay it in XP from the sponsor's pool

A sponsor's ad campaign can lead to a draw on your site: the creative clicks
through to a page where a signed-in fan enters to win something the sponsor
offers. When the fan enters, your backend reports the entry to 4D. 4D stores
one entry per fan and campaign, counts it in the sponsor's campaign stats,
and can pay the fan XP for it from the sponsor's own pool.

## Report an entry

Call it from your server with an organization `org_` key and the fan's id in
your own system. Never call it from a browser or with a publishable key.

```bash theme={null}
curl -X POST "$API_BASE_URL/v1/ads/campaigns/$CAMPAIGN_ID/entries" \
  -H "Authorization: Bearer $ORG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "member_external_id": "fan-1042" }'
```

```json theme={null}
{
  "entry": {
    "status": "recorded",
    "campaign_id": "0199a3c1-7e2b-7c41-9a0e-5b8f6d2e4a10",
    "advertiser_name": "Northwind Air",
    "xp": "funded"
  }
}
```

`status` is one of three outcomes, all answered `200`:

| `status` | What happened |
| - | - |
| `recorded` | The fan holds your **Personalised content** consent and had not entered this campaign. The entry is stored with the fan. |
| `duplicate` | The fan has already entered. Nothing is stored and no XP is paid, however often you call or however the calls race. |
| `anonymous` | The fan does not hold the consent. The entry is counted without the fan and pays no XP. |

Only a fan who holds the consent is deduplicated. An entry from a fan
without it is stored anonymously and counted on **every** call, so a retry,
a second device or a later entry by the same fan each add one to the
campaign's entries. Retrying a call for a fan who holds the consent is
always safe. For a fan without it, a retry after an answer you never
received can count the same entry twice.

The consent is the tenant consent item titled "Personalised content", scope
`org.<your organization id>.personalised-content`.

Errors:

| Status | When |
| - | - |
| `404 NOT_FOUND` | The campaign is not yours, or no active member has that `member_external_id`. |
| `409 AD_CAMPAIGN_INVALID_STATE` | The campaign is not running: not active, or outside its start and end dates. |
| `422 VALIDATION_ERROR` | The campaign id is not a UUID, or the body is not `{ "member_external_id": "<string>" }`. |

## XP for an entry

`xp` is `funded` when the sponsor's XP pool pays this entry, and `none`
otherwise. Three things have to hold:

1. The ad campaign is linked to the sponsor's XP campaign (its pool). Set
   the link on the ad campaign as `xp_campaign_id`.
2. An earning rule pays an entry on this campaign from that pool. An entry
   arrives as the earning event `engagement.content.viewed` with
   `content_type` `ad_campaign_entry` and `content_id`
   `ad_campaign_entry:<ad campaign id>`, so the rule is a case on
   **Content viewed** whose condition is `content_id` equal to that value,
   funded by the sponsor's campaign. A case that matches is paid instead of
   the key's default, so your ordinary content-view award never pays an
   entry. Only 4D produces that content id: an event from one of your
   modules carrying it, or carrying the `ad_campaign_entry` content type, is
   refused at `/v1/ingest` with `reserved_ad_entry_marker`, so no content
   view your site sends can be paid from the sponsor's pool.
3. The pool is active, inside its dates, and holds at least the award.

When any of these does not hold the entry is still recorded, with `xp`
`none`, and nothing is paid from your own reserve.

The award is paid asynchronously, through the same path as every other XP
award: your [earning controls](https://docs.fourdos.dev/concepts/earning-events.md) apply and the fan's
balance moves a moment later. The response never carries an amount, and a
`funded` entry can still earn nothing if a control refuses it, such as a
member's daily cap. Because an entry is a **Content viewed** event, any
daily or lifetime limit you set on content views counts entries too: a fan
who has used up their content-view limit for the day can enter with `xp`
`funded` and earn nothing for it. See [XP](https://docs.fourdos.dev/concepts/xp.md) for
sponsor-funded campaigns.

## What the sponsor sees

The sponsor's campaign stats count entries, anonymous ones included, and
the number of fans who engaged with the campaign. They never show a fan's
name or id.


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