# Server routes API

> Routes your backend calls: winner contact, fulfillment acknowledgements and streak callbacks.

Source: https://dashboard.adquest.batriders.ir/docs/api/server-routes · Audience: Developers · Section: API reference

## Post a winner’s contact

### `POST /platform/lottery-claims/{claimId}/contact`

Sends AdQuest the winner’s email after a lottery.winner webhook, so AdQuest can notify them. Call it only for the winner of that claim.

**Authentication:** Secret Key, sent as the X-AdQuest-Platform-Secret header. Backend only.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| claimId | path | integer | yes | Claim ID from the lottery.winner webhook. |
| external_user_id | body | string | yes | Your ID for the winner. Max 255 characters. |
| email | body | string | yes | The winner’s email. Max 255 characters. |
| display_name | body | string | yes | The winner’s name. Max 255 characters. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/lottery-claims/91/contact \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Secret: YOUR_SECRET_KEY" \
  -d '{
  "external_user_id": "player-42",
  "email": "ada@example.com",
  "display_name": "Ada"
}'
```

**Response 200.** The contact was received.

```json
{
  "status": true,
  "code": "OK",
  "message": "Winner contact received",
  "data": {
    "claim_id": 91,
    "notified": true
  }
}
```

**Response 401.** The Secret Key is missing or wrong.

**Response 403.** The platform is not accepted and active.

**Response 404.** CLAIM_NOT_AVAILABLE.

**Response 429.** RATE_LIMITED. Too many contact requests.

## Acknowledge a fulfillment

### `POST /platform/fulfillments/{fulfillmentId}/acknowledge`

Confirms that you delivered a reward announced by a fulfillment.requested webhook. Repeating the same external_reference is safe.

**Authentication:** Public API key (X-AdQuest-Platform-Key).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| fulfillmentId | path | integer | yes | Fulfillment ID from the webhook. |
| external_reference | body | string | yes | Your own reference for the delivered reward. Max 190 characters. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/fulfillments/12/acknowledge \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -d '{ "external_reference": "order-8841" }'
```

**Response 200.** The fulfillment was acknowledged. data has id, kind, status, amount, asset, external_reference, last_failure_reason, acknowledged_at, quest_completion_id, lottery_claim_id and created_at.

**Response 404.** The fulfillment was not found.

**Response 409.** FULFILLMENT_CONFLICT. It was already acknowledged with a different external_reference.

## Record a streak day from the creator callback URL

### `POST /streak-callbacks/{token}`

Records one day of a streak quest. Call the callback URL from your backend after the user finishes that day’s action. GET works too, with user_id as a query parameter. A streak STEP of a multi-step quest has its own per-participant callback URL (callback_url in that step of the execution state); user_id is then optional and, if sent, must match the participant. The last day verifies only that step; the parent quest settles separately (data.step_verified, data.settlement_status).

**Authentication:** None.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| token | path | string | yes | The 64-character hex token from the quest’s callback URL. |
| Idempotency-Key | header | string | no | Optional key to make a retry safe. |
| user_id | body | string | yes | Your stable ID for the user. external_user_id, userId and externalUserId are accepted as aliases. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/streak-callbacks/CALLBACK_TOKEN \
  -H "Content-Type: application/json" \
  -d '{ "user_id": "player-123" }'
```

**Response 200.** The day was recorded. On the last day the quest completes and data also holds tokens_awarded.

```json
{
  "status": true,
  "code": "OK",
  "message": "Streak day recorded",
  "data": {
    "completed": false,
    "quest_id": 7800,
    "external_user_id": "player-123",
    "streak": {
      "current_day": 2,
      "day_count": 7,
      "status": "active",
      "unlocked": false,
      "next_unlock_at": "2026-09-14T12:00:00+00:00",
      "last_completed_day": 1,
      "day_number": 1,
      "micro_rewarded": false,
      "final_rewarded": false,
      "idempotent": false
    }
  }
}
```

**Response 404.** STREAK_CALLBACK_NOT_FOUND. The token does not match a quest.

**Response 422.** INVALID_STREAK_USER or another streak error. data.reason says why.

**Response 429.** RATE_LIMITED.

## Record a streak day (GET)

### `GET /streak-callbacks/{token}`

Same as the POST route, with user_id as a query parameter. Use POST when you can.

**Authentication:** None.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| token | path | string | yes | The 64-character hex token from the quest’s callback URL. |
| user_id | query | string | yes | Your stable ID for the user. external_user_id is accepted as an alias. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/streak-callbacks/CALLBACK_TOKEN?user_id=player-123"
```

**Response 200.** The day was recorded. On the last day the quest completes and data also holds tokens_awarded.

```json
{
  "status": true,
  "code": "OK",
  "message": "Streak day recorded",
  "data": {
    "completed": false,
    "quest_id": 7800,
    "external_user_id": "player-123",
    "streak": {
      "current_day": 2,
      "day_count": 7,
      "status": "active",
      "unlocked": false,
      "next_unlock_at": "2026-09-14T12:00:00+00:00",
      "last_completed_day": 1,
      "day_number": 1,
      "micro_rewarded": false,
      "final_rewarded": false,
      "idempotent": false
    }
  }
}
```

**Response 404.** STREAK_CALLBACK_NOT_FOUND. The token does not match a quest.

**Response 422.** INVALID_STREAK_USER or another streak error. data.reason says why.

**Response 429.** RATE_LIMITED.

## Next steps

- [Webhook events](https://dashboard.adquest.batriders.ir/docs/api/webhook-events): The notifications that lead to these calls.
- [Webhooks guide](https://dashboard.adquest.batriders.ir/docs/webhooks): Register and verify an endpoint.
