Season pass

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 statusJSON responseMeaning
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://localhost is 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 Authorization header and moumint_action_token query 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.

On this page