Action Webhook Quests
Connect a partner action to a Season Pass quest with an authenticated callback.
An Action Webhook Quest lets a partner confirm an action for one player. The partner sends the opaque token from the player's action URL to the tenant's public callback endpoint. Moumint marks the quest complete, and the player can claim the resulting reward later.
Callback endpoint
Use the tenant's public host and this fixed endpoint for every Action Webhook Quest:
POST https://tenant.example.com/api/quest/action-webhook/complete
Authorization: Bearer <Quest Callback Secret>
Content-Type: application/json
{"actionToken":"<moumint_action_token value>"}The endpoint is host-routed. Do not add a tenant header, tenant field, quest ID, or a per-quest endpoint path. The callback secret identifies the configured tenant quest; the request body must contain exactly one field, actionToken.
Token handoff
The player-facing Action Webhook URL contains a fixed query parameter named moumint_action_token. Copy that parameter's value from the incoming URL and return it unchanged as actionToken.
Do not decode, edit, URL-normalize, regenerate, or share the token. It is opaque and bound to the tenant, player, quest, season assignment, and assignment lifecycle. A new token is issued when the player starts the action; repeated starts for the same lifecycle produce a stable token.
Responses and retries
| HTTP status | JSON response | Meaning |
|---|---|---|
200 | {"status":"completed"} | The first valid callback completed the quest. |
200 | {"status":"already_completed"} | The callback was a durable duplicate. Treat it as success, including after quest closure. |
400 | {"code":"invalid_action_token"} | The token is malformed, altered, for another tenant or quest, or no longer valid. |
401 | {"code":"unauthorized"} | The Bearer secret is missing or incorrect. No token or quest detail is returned. |
409 | {"code":"player_ineligible"} | The player is no longer eligible, including a deliberately discarded guest handoff. |
410 | {"code":"quest_closed"} | The first callback is outside the assigned live season or the quest is no longer assigned. |
Retry only 5xx responses. A 2xx response is terminal success; do not retry either successful status. Do not retry the documented 4xx responses without correcting the underlying configuration or player state. Concurrent duplicate callbacks resolve to already_completed.
The callback only records completion. XP, coins, and any selected reward are delivered when the player later claims the pending reward. Existing earned rewards remain claimable after a season or quest closes.
Security and logging
- Send callbacks only over HTTPS.
http://localhostis allowed for local development and testing; production callback traffic must use HTTPS. - Store the Quest Callback Secret in the partner's secret manager and send it only as the Bearer credential.
- Never log, trace, store in analytics, or include in error reports the callback secret or the full action token. Redact the
Authorizationheader andmoumint_action_tokenquery parameter before request logging. - Do not put secrets or tokens in URLs copied to tickets, screenshots, dashboards, or third-party analytics. If a token must be correlated, use a separately generated internal request ID.
- Do not use live credentials in development examples or tests. The values above are placeholders only.
Minimal implementation
const token = new URL(playerActionUrl).searchParams.get("moumint_action_token");
await fetch("https://tenant.example.com/api/quest/action-webhook/complete", {
method: "POST",
headers: {
Authorization: `Bearer ${questCallbackSecret}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ actionToken: token }),
});Treat token === null as an integration error and do not send an empty callback. Keep the callback secret server-side; this request must not run in browser code.