OpenPoly logo
Webhooks

Event types

Business events sent by OpenPoly to operator webhook receivers.

Event types

Current event list comes from packages/mini-app/src/types.ts.

Source-of-truth list

  • mini_app.login.succeeded
  • mini_app.trade.submitted
  • mini_app.trade.processed
  • mini_app.trade.failed
  • mini_app.trade.compensation_required
  • mini_app.redemption.processed
  • mini_app.redemption.failed
  • mini_app.payout.pending
  • mini_app.logout.requested
  • mini_app.session.expired

Payload reference

Current durable callback delivery reconstructs data at send time for aggregate_type = mini_app_order. That means trade callback data is operator-actionable even if the stored outbox payload is minimal.

Trade order data fields

Trade events with aggregate_type = mini_app_order use this data family:

  • order_id
  • trade_id
  • executed_trade_id
  • operator_id
  • operator_user_id
  • polynion_user_id
  • external_user_id
  • market_id
  • side: buy or sell
  • outcome: yes or no
  • status
  • requested_external_amount_minor
  • requested_shares_micro
  • quoted_credits_equivalent
  • quoted_external_amount_minor
  • shares_micro
  • balance_spent
  • trade_fee
  • trade_fee_credits
  • currency_code
  • fx_rate_snapshot_id
  • failure_reason

Do not expect legacy credits_delta or external_amount_minor in trade callback data.

trade_fee is historical fee in integer minor units of currency_code, matching Operator Trade Fees view. trade_fee_credits is same fee denominated in Credits.

mini_app.login.succeeded

Allowlisted event name for launch/session lifecycle. Current durable processor paths do not define an operator-actionable payload beyond the common envelope.

mini_app.trade.submitted

Allowlisted event name for order submission. Current durable trade processor callbacks use the processed, failed, or compensation-required terminal events below.

mini_app.trade.processed

Sent when trade completed successfully.

{
  "order_id": 123,
  "trade_id": 456,
  "executed_trade_id": 456,
  "operator_id": 12,
  "operator_user_id": 34,
  "polynion_user_id": 789,
  "external_user_id": "operator-user-123",
  "market_id": 51,
  "side": "buy",
  "outcome": "yes",
  "status": "processed",
  "requested_external_amount_minor": 10000,
  "requested_shares_micro": null,
  "quoted_credits_equivalent": 6340,
  "quoted_external_amount_minor": 10000,
  "shares_micro": 1234500,
  "balance_spent": 10000,
  "trade_fee": 39,
  "trade_fee_credits": 25,
  "currency_code": "IDR",
  "fx_rate_snapshot_id": 88,
  "failure_reason": null
}

mini_app.trade.failed

Sent when trade fails and no successful final execution exists.

{
  "order_id": 123,
  "trade_id": null,
  "executed_trade_id": null,
  "operator_id": 12,
  "operator_user_id": 34,
  "polynion_user_id": 789,
  "external_user_id": "operator-user-123",
  "market_id": 51,
  "side": "buy",
  "outcome": "yes",
  "status": "failed",
  "requested_external_amount_minor": 10000,
  "requested_shares_micro": null,
  "quoted_credits_equivalent": 6340,
  "quoted_external_amount_minor": 10000,
  "shares_micro": null,
  "balance_spent": 10000,
  "trade_fee": null,
  "trade_fee_credits": null,
  "currency_code": "IDR",
  "fx_rate_snapshot_id": null,
  "failure_reason": "OPERATOR_DEBIT_FAILED"
}

mini_app.trade.compensation_required

Sent when wallet debit happened but downstream completion needed manual or compensating handling.

{
  "order_id": 123,
  "trade_id": null,
  "executed_trade_id": null,
  "operator_id": 12,
  "operator_user_id": 34,
  "polynion_user_id": 789,
  "external_user_id": "operator-user-123",
  "market_id": 51,
  "side": "buy",
  "outcome": "yes",
  "status": "compensation_pending",
  "requested_external_amount_minor": 10000,
  "requested_shares_micro": null,
  "quoted_credits_equivalent": 6340,
  "quoted_external_amount_minor": 10000,
  "shares_micro": null,
  "balance_spent": 10000,
  "trade_fee": null,
  "trade_fee_credits": null,
  "currency_code": "IDR",
  "fx_rate_snapshot_id": null,
  "failure_reason": "DB_EXECUTION_FAILED_AFTER_DEBIT"
}

mini_app.redemption.processed

Sent when redemption or payout completed successfully.

{
  "redemption_item_id": 77,
  "run_id": 9,
  "redeem_request_id": 88,
  "operator_id": 12,
  "operator_user_id": 34,
  "external_amount_minor": 15000,
  "fx_rate_snapshot_id": 91
}

mini_app.redemption.failed

Sent when redemption flow failed before successful credit completion.

{
  "redemption_item_id": 77,
  "run_id": 9,
  "operator_id": 12,
  "operator_user_id": 34,
  "status": "manual_review",
  "failure_reason": "OPERATOR_CREDIT_FAILED"
}

mini_app.payout.pending

Allowlisted event name for payout follow-up. Current Mini App redemption processor emits mini_app.redemption.failed with status = manual_review for unresolved payout-side failures.

mini_app.logout.requested

Allowlisted event name for operator-side session cleanup. Current durable processor paths do not define an operator-actionable payload beyond the common envelope.

mini_app.session.expired

Allowlisted event name for launched Mini App session expiry. Current durable processor paths do not define an operator-actionable payload beyond the common envelope.

Guidance

  • keep receiver tolerant to additive fields
  • branch only on known event_type
  • use event_id for dedupe
  • for current trade callbacks, prefer order_id, trade_id / executed_trade_id, operator_user_id, external_user_id, and market_id for support correlation
  • for current redemption callbacks, prefer redemption_item_id, run_id, redeem_request_id, operator_user_id, and external_amount_minor when present
  • treat failure_reason as operator-facing diagnostic string, not enum guaranteed forever
  • examples above are source-backed where current contract already defines fields explicitly
Copyright © 2026