# Quest actions API

> Send the evidence each quest format needs, then complete the quest.

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

## How completion works

Each quest format collects its own evidence, then the quest is completed. Timed quests use start, progress and complete. Survey and video quests also read the question. Visit, event, referral, profile and custom quests send their own evidence first. Streak quests are completed from the callback URL, not from complete.

- [Quest evidence](https://dashboard.adquest.batriders.ir/docs/quest-evidence): The evidence each format requires.
- [Quests API](https://dashboard.adquest.batriders.ir/docs/api/quests): List, read, start, click and view.

## Get the question

### `GET /platform/quests/{questId}/question`

Returns the question and its options for a video, banner or survey quest. The quest must have been started for this user.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| external_user_id | query | string | yes | Your ID for the user. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/question" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The first question, plus questions for surveys with several. Also returned with this status: status is false when external_user_id is missing, the quest was not started or its timer expired, or the quest has no question. The message says which.

```json
{
  "status": true,
  "code": "OK",
  "message": "Quest question",
  "data": {
    "id": 5,
    "title": "What did the video explain?",
    "input_type": "choice",
    "is_required": true,
    "options": [
      {
        "id": 11,
        "title": "How to start"
      },
      {
        "id": 12,
        "title": "How to pay"
      }
    ],
    "questions": []
  }
}
```

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

## Record watch progress

### `POST /platform/quests/{questId}/progress`

Records watch evidence for a timed quest. Send it while the participant is really watching.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| external_user_id | body | string | yes | Your ID for the user. Max 255 characters. |
| watch_duration | body | number | no | Seconds watched so far. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/progress \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{ "external_user_id": "player-42", "watch_duration": 8 }'
```

**Response 200.** The progress was recorded.

```json
{
  "status": true,
  "code": "OK",
  "message": "Quest progress recorded",
  "data": {
    "quest_id": 23,
    "elapsed_seconds": 8,
    "required_seconds": 15
  }
}
```

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

**Response 422.** The evidence was rejected. data.reason says why. If the quest is already completed, data.completed is true.

## Record a progress metric

### `POST /platform/quests/{questId}/metrics`

Adds a measured amount to a quest that completes when a progress target is reached.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| external_user_id | body | string | yes | Your ID for the user. Max 255 characters. |
| event_id | body | string | yes | Your unique ID for this measurement. Max 128 characters. |
| amount | body | number | yes | The amount to add. |
| occurred_at | body | string | yes | When it happened. Must fall inside the quest’s activity window. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/metrics \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{
  "external_user_id": "player-42",
  "event_id": "evt_1001",
  "amount": 5,
  "occurred_at": "2026-01-01T12:00:00Z"
}'
```

**Response 200.** The metric was recorded. data holds the participant’s progress snapshot.

**Response 403.** PREVIEW_READONLY. A theme preview cannot record progress.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

**Response 422.** PROGRESS_UNSUPPORTED if the quest does not track progress, or another error code if the event was rejected.

## Attribute a visit

### `GET /platform/quests/{questId}/visit`

Records that the participant followed the link of a visit quest and returns the destination. Visit quests only.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| external_user_id | query | string | yes | Your ID for the user. May also be sent in the body. |
| referrer_external_user_id | query | string | no | The user who shared the link, if any. |
| redirect | query | string | no | Send 1 to receive an HTTP redirect to the destination instead of JSON. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/visit" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The visit was attributed.

```json
{
  "status": true,
  "code": "OK",
  "message": "Visit attributed",
  "data": {
    "quest_id": 23,
    "redirect_url": "https://example.com/offer",
    "clicked_at": "2026-01-01T12:00:00.000Z"
  }
}
```

**Response 400.** NOT_VISIT_QUEST. The quest is not a visit quest.

**Response 401.** PARTICIPANT_AUTH_REQUIRED. external_user_id is missing.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

## Send a verified event

### `POST /platform/quests/{questId}/events`

Sends an event your app or server observed, such as a purchase, for event and custom quests.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| external_user_id | body | string | yes | Your ID for the user. May also be sent as a query parameter. |
| event_id | body | string | yes | Your unique ID for the event. Sending the same ID again returns duplicate: true. |
| event_name | body | string | yes | The event the quest is waiting for. |
| source | body | string | no | Where the event came from. Defaults to sdk. |
| timestamp | body | string | no | When the event happened. |
| signature | body | string | no | Signature for server-signed events. |
| delivery_token | body | string | no | Token from the quest start. May instead be sent as the X-AdQuest-Delivery-Token header. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/events \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{
  "external_user_id": "player-42",
  "event_id": "evt_1001",
  "event_name": "purchase_completed"
}'
```

**Response 200.** The event was accepted.

```json
{
  "status": true,
  "code": "OK",
  "message": "Event accepted",
  "data": {
    "quest_id": 23,
    "event_id": "evt_1001",
    "event_name": "purchase_completed",
    "duplicate": false,
    "verified_at": "2026-01-01T12:00:00.000Z"
  }
}
```

**Response 401.** PARTICIPANT_AUTH_REQUIRED. external_user_id is missing.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

**Response 422.** The event was rejected. data.code says why.

## Attribute a referral

### `POST /platform/quests/{questId}/referrals`

Credits the inviter when a new user arrives with their referral code. Referral quests only.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| external_user_id | body | string | yes | The invited user. May also be sent as a query parameter. |
| referral_code | body | string | yes | The inviter’s code. Max 32 characters. |
| device_fingerprint | body | string | no | Max 128 characters. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/referrals \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{ "external_user_id": "player-77", "referral_code": "ADA123" }'
```

**Response 200.** Referral attributed.

**Response 401.** PARTICIPANT_AUTH_REQUIRED. external_user_id is missing.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

**Response 422.** NOT_REFERRAL_QUEST if the quest is not a referral quest, or a referral error code in data.code.

## Answer one question

### `POST /platform/quests/{questId}/answer`

Answers the current question of the participant's attempt, in order and before its deadline. The last answer submits the attempt: it is accepted (202) and settled asynchronously; poll the completion status. Needs a reservation (the quest was started with reservations enabled). A request naming an earlier reservation_id is refused with 409 STALE_RESERVATION and changes nothing. A retry of the accepted final answer returns 202 (still processing) or the settled outcome, even after the attempt's deadline; it never creates a second submission.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| question_id | body | integer | yes | The current question. |
| option_id | body | integer | no | The chosen option (choice questions). |
| free_text | body | string | no | The answer (free-text questions). |
| reservation_id | body | string | no | The reservation_id returned by start (or the X-AdQuest-Reservation header). Required: an answer must name its attempt, and it must be the current one (409 STALE_RESERVATION otherwise, 422 RESERVATION_REQUIRED when missing). |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/answer \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{ "question_id": 5 }'
```

**Response 200.** The answer was recorded; the next question's deadline is in the data. correct is false when a video or banner quiz question was missed for the first time: the attempt goes on and the question is asked once more after the others (ask_order lists the question ids in the order they are asked). A second miss on it ends the attempt (ANSWER_REJECTED).

```json
{
  "status": true,
  "code": "OK",
  "message": "Answer recorded",
  "data": {
    "state": "reserved",
    "correct": true,
    "answered_count": 1,
    "ask_order": [
      5,
      6
    ],
    "question_due_at": "2026-11-07T10:00:22+00:00"
  }
}
```

**Response 202.** The final answer was accepted. The attempt is processing: capacity and budget stay reserved until settlement.

```json
{
  "status": true,
  "code": "ACCEPTED",
  "message": "Answer accepted",
  "data": {
    "state": "processing",
    "reservation_id": "0f4f6c52-3c7d-4d6e-9d0f-6f9d3f1d2a11",
    "settlement_status": "pending",
    "quest_id": 23
  }
}
```

**Response 409.** RESERVATION_EXPIRED, WRONG_QUESTION, STALE_RESERVATION or TOO_EARLY.

**Response 422.** The answer is not valid for the question.

## Read growth status

### `GET /platform/quests/{questId}/growth-status`

Returns where the participant stands on a profile, referral, streak or custom quest.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| external_user_id | query | string | yes | Your ID for the user. May also be sent in the body. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/growth-status" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** data.type is the quest format. A profile quest adds data.profile with the completeness check. A referral quest adds data.referral with the participant’s code, invite link and attributed count. Streak and custom quests add their own state.

**Response 401.** PARTICIPANT_AUTH_REQUIRED. external_user_id is missing.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

## Complete a quest

### `POST /platform/quests/{questId}/complete`

Submits the participant’s evidence. AdQuest checks it on the server and, when it is valid, settles the reward.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| Idempotency-Key | header | string | no | Send as an HTTP header. A repeated key returns the earlier completion and never pays twice. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| external_user_id | body | string | yes | Your ID for the user. Max 255 characters. |
| question_id | body | integer | no | Required for video and banner quests, and for surveys when answers is not sent. |
| user_input | body | string | no | The option the participant chose. Required together with question_id. |
| answers | body | array | no | Survey only. One entry per answered question, each with its question_id. |
| delivery_token | body | string | no | Token you received when the quest started. |
| watch_duration | body | number | no | Seconds watched. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/complete \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{
  "external_user_id": "player-42",
  "question_id": 5,
  "user_input": "11"
}'
```

**Response 200.** The quest was completed. tokens_awarded is the participant’s share.

```json
{
  "status": true,
  "code": "OK",
  "message": "Quest completed successfully",
  "data": {
    "status": true,
    "quest_id": 23,
    "completed_at": "2026-01-01T12:00:00.000Z",
    "tokens_awarded": 10,
    "token_reward": 10
  }
}
```

**Response 403.** PREVIEW_READONLY. A theme preview cannot complete quests.

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

**Response 422.** Validation failed, the evidence was rejected, or the quest is a streak quest. STREAK_CALLBACK_REQUIRED means the day must be submitted from the callback URL.

> **The response does not carry a settlement status.** Read status and data. The SDK derives its settlementStatus from them. Confirm the reward with a signed webhook before you grant anything permanent in your own app.

## Check a completion

### `GET /platform/quests/{questId}/completion`

Where the participant's attempt stands: reserved, processing, settled, rejected or expired, with the settlement status and the tokens awarded once settled.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/completion" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The attempt's state. settlement_status is success, pending, failed or none.

```json
{
  "status": true,
  "code": "OK",
  "message": "Completion status",
  "data": {
    "quest_id": 23,
    "state": "settled",
    "reservation_id": "0f4f6c52-3c7d-4d6e-9d0f-6f9d3f1d2a11",
    "settlement_status": "success",
    "tokens_awarded": 7,
    "reason": null,
    "expires_at": null,
    "completed_at": "2026-11-07T10:00:41+00:00"
  }
}
```

## Read quest stats

### `GET /platform/quests/{questId}/stats`

Returns engagement counts for one quest on your platform.

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

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | no | The participant token. Optional here. It adds per-user state such as completed. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/stats" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** seen_count is participants who started the quest, clicked_count those who clicked, and answered_count those who completed it. engagement_rate is completed ÷ started as a percentage.

```json
{
  "status": true,
  "code": "OK",
  "message": "Quest stats",
  "data": {
    "id": 23,
    "name": "Watch our intro video",
    "seen_count": 120,
    "clicked_count": 40,
    "answered_count": 54,
    "engagement_rate": 45
  }
}
```

**Response 404.** QUEST_NOT_FOUND. The quest does not exist or is not available.

## Check a manual review

### `GET /platform/quests/{questId}/review`

Where the participant's manual_review submission stands: pending, approved, rejected or expired. Approval completes the quest and settles the reward without a second request; an approved review that is still settling retries here. A rejected or expired review may be resubmitted through the complete endpoint while can_resubmit is true. Returns status none before any submission.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/review" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The latest review for the participant. settlement_status is pending or settled once approved, otherwise null.

```json
{
  "status": true,
  "code": "OK",
  "message": "Custom review status",
  "data": {
    "id": 41,
    "status": "rejected",
    "attempt": 1,
    "evidence": "receipt-123",
    "approved_at": null,
    "rejected_at": "2026-11-08T09:12:00+00:00",
    "reject_reason": "Receipt is unreadable",
    "expires_at": "2026-11-22T09:00:00+00:00",
    "settled_at": null,
    "can_resubmit": true,
    "settlement_status": null
  }
}
```

## Read a multi-step execution

### `GET /platform/quests/{questId}/execution`

State of the participant's multi-step execution: the definition version it is bound to, every step with its status (pending, in_review, verified, rejected) and availability, whether all required steps are verified, and the settlement status of the parent quest. Returns 409 NOT_STARTED before start. Disabled (404 MULTI_STEP_DISABLED) unless the multi-step feature flag is on.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/execution" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The execution state.

```json
{
  "status": true,
  "code": "OK",
  "message": "Execution state",
  "data": {
    "quest_id": 23,
    "execution_id": 7,
    "steps_version": 1,
    "ordering": "sequential",
    "state": "reserved",
    "steps": [
      {
        "step_key": "buy",
        "position": 1,
        "format": "custom",
        "required": true,
        "status": "verified",
        "attempts": 1,
        "available": true
      }
    ],
    "steps_complete": false,
    "settlement_status": "none",
    "unsettled_reason": null,
    "tokens_awarded": null
  }
}
```

## Read one step

### `GET /platform/quests/{questId}/steps/{key}`

Status of one step of the execution, including the latest manual review (never expected answers or callback URLs). When the owner or the platform's activity definition set a host deep link, config carries action_url (https or an app scheme) and an optional action_label; the SDK only navigates to it and the host app still proves the step.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| key | path | string | yes | Step key. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |

```bash
curl "https://api.adquest.batriders.ir/api/v1/platform/quests/23/steps/buy" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN"
```

**Response 200.** The execution state.

```json
{
  "status": true,
  "code": "OK",
  "message": "Execution state",
  "data": {
    "quest_id": 23,
    "execution_id": 7,
    "steps_version": 1,
    "ordering": "sequential",
    "state": "reserved",
    "steps": [
      {
        "step_key": "buy",
        "position": 1,
        "format": "custom",
        "required": true,
        "status": "verified",
        "attempts": 1,
        "available": true
      }
    ],
    "steps_complete": false,
    "settlement_status": "none",
    "unsettled_reason": null,
    "tokens_awarded": null
  }
}
```

## Submit step evidence

### `POST /platform/quests/{questId}/steps/{key}/evidence`

Ask the server to verify a step. The server decides: a body of completed:true is ignored. action=start starts a timed (video/banner) step, action=click records a visit click, evidence/answers/evidence_type carry survey answers or manual-review proof. Server-attested events are sent to POST /events with step_key and a v2 signature (v2.eventId.eventName.questId.participantId.timestamp.stepKey.stepsVersion.executionId, HMAC-SHA256). When the last required step is verified the parent is admitted for settlement without another request; poll the execution or completion for the result.

**Authentication:** Public API key (X-AdQuest-Platform-Key) and participant token (X-AdQuest-Participant-Token). Both are required.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| questId | path | integer | yes | Quest ID. |
| key | path | string | yes | Step key. |
| X-AdQuest-Participant-Token | header | string | yes | The participant token minted by your backend (POST /platform/participant-sessions). Required: it is the participant's identity. A body external_user_id is optional and must match it (403 PARTICIPANT_MISMATCH); a missing or invalid token is 401 PARTICIPANT_AUTH_REQUIRED. |
| action | body | string | no | start begins a timed (video/banner) step; click records the click of a visit step. Omit to submit evidence. |
| evidence | body | string | no | Proof text for a manual_review step (max 2000 characters). |
| evidence_type | body | string | no | Evidence type the step expects (must match the step configuration). |
| answers | body | array | no | Survey answers: [{question_id, user_input}]. |

```bash
curl -X POST https://api.adquest.batriders.ir/api/v1/platform/quests/23/steps/buy/evidence \
  -H "Content-Type: application/json" \
  -H "X-AdQuest-Platform-Key: YOUR_PUBLIC_API_KEY" \
  -H "X-AdQuest-Participant-Token: PARTICIPANT_TOKEN" \
  -d '{  }'
```

**Response 200.** The execution state.

```json
{
  "status": true,
  "code": "OK",
  "message": "Execution state",
  "data": {
    "quest_id": 23,
    "execution_id": 7,
    "steps_version": 1,
    "ordering": "sequential",
    "state": "reserved",
    "steps": [
      {
        "step_key": "buy",
        "position": 1,
        "format": "custom",
        "required": true,
        "status": "verified",
        "attempts": 1,
        "available": true
      }
    ],
    "steps_complete": false,
    "settlement_status": "none",
    "unsettled_reason": null,
    "tokens_awarded": null
  }
}
```

**Response 202.** Evidence accepted for asynchronous review.

**Response 409.** STEP_OUT_OF_ORDER, STEP_NOT_STARTED, RESERVATION_EXPIRED, NOT_STARTED or QUEST_PROCESSING.

**Response 422.** The server could not verify the step from the evidence (CLICK_REQUIRED, TIMER_NOT_FINISHED, CUSTOM_EVIDENCE_MISSING, ...).
