Skip to main content
Send Slack alerts for recorded large Polymarket trades from S- and A-grade wallets. Save the last completed event after Slack acknowledges the alert, so a restart resumes from that point. This consumer delivers at least once: a crash after Slack accepts an alert but before the checkpoint is saved can send the same alert again. The example also stops progress when trade details are unavailable, rather than silently skipping the event. You need a Pro API key, Python with requests, and a Slack incoming webhook URL. Run python -m pip install requests, then set OXINSIDER_API_KEY and SLACK_WEBHOOK_URL in your environment. Combine steps 2 through 6 into one script in their displayed order.

1. Choose how to receive events

Use Event replay to read trades after a saved cursor. A webhook or SSE connection can wake the consumer sooner, but the replay cursor determines which trades still need processing. Start with polling alone. Add a webhook or stream if you need lower notification latency.

2. Save a local checkpoint

Store the last completed event’s cursor and recent delivered event IDs in a file. os.replace replaces the file atomically, so a process interruption does not leave a partially written JSON document.
The first run has no cursor and starts with recent events. It does not read all historical trades. To begin from an existing position, save a cursor returned by an earlier replay request. Run one consumer per state file. The example does not coordinate concurrent processes or guarantee durability after a machine loses power.

3. Handle API failures

The helper retries temporary responses and connection failures, leaving the checkpoint unchanged. Permanent errors stop the process with the API’s message.
A monthly quota failure stops immediately even though its status is 429. Read its reset time or adjust account usage on Developers. Do not keep a process asleep until next month. A 400 caused by changed cursor filters also stops. Restore the previous filters, or deliberately start a new traversal without the old cursor.

4. Post one alert

The consumer requests min_grade=A, so every returned trade has an S or A grade. Names are optional and are read with .get().
Slack’s incoming webhook documentation defines a successful acknowledgement as HTTP 200 with ok. The example checks both before allowing the checkpoint to advance. For another destination, replace post_alert and require that destination’s documented acknowledgement. Use an idempotency key when it supports one.

5. Process events in order

The replay request uses min_grade=A, min_size=25000, and expand=trade. It receives trades worth at least $25,000 and includes their base large-trade fields in the same response.
The cursor advances only after deliver returns. A failed post or a null trade raises first, so the next attempt starts from the same uncompleted event. After the last page, save next_cursor even if the page is empty. It can advance past rows that did not match your filters, avoiding repeated reads of those rows.

Fields to keep straight

trader, condition_id, min_grade, and min_size are tied to the cursor. Changing them returns 400 with cursor_expired. Changing expand is allowed. Replay cursors do not expire because of age. meta.retention.cursor_expired is always false; the error with the same name describes an incompatible cursor or filter combination.

6. Run the consumer

The loop checks every 15 seconds while caught up, or every 5 seconds when the feed reports pending records. Failed delivery keeps the current checkpoint and waits 30 seconds before trying again.
A page contains up to 100 events and costs 1 request. Idle polling uses 4 requests per minute from the account’s shared 100-request-per-minute budget. See Rate limits. If an event keeps returning trade: null, inspect that event and its detail route. The example holds the checkpoint indefinitely; decide how your application records and handles an event whose details cannot be recovered before intentionally skipping it.

7. Add a webhook or stream wake-up

Both mechanisms notify you of new trade records. Keep the replay loop as the consumer and call wake.set() to start its next read sooner.

Webhook

Register a destination for whale_trades_inserted and verify it as described in Webhooks. Verify the request signature before passing the event to this handler sketch:
Answer within the delivery’s 15-second timeout. Run the replay work outside the HTTP handler. The event contains a count, not the trade object.

SSE stream

Request Stream with event=WhaleTradesInserted:
Use a stream reader in your application to call wake.set() when a frame arrives. Each frame has an id and a JSON body containing seq, published_at, type, and count. Send Last-Event-ID when reconnecting. A resync means retained stream history cannot cover that gap; the replay loop still resumes from its durable cursor. Do not add condition_id or min_grade to this stream subscription. These count-only frames lack those fields and would all be filtered out. An open-stream cap can return 429; honor Retry-After before reconnecting.

Delivery and coverage limits

  • Alerts describe already executed trades. traded_at is the fill time, and replay begins when 0xinsider records the trade.
  • Coverage includes recorded large trades, not every Polymarket fill.
  • The current grade, username, and review_score can change before you read an event. recorded_review_score and trader.grade_at_trade record trade-time values when available.
  • A crash between delivery and checkpoint storage can produce a duplicate. Exactly-once posting requires support from the destination.
  • An unavailable trade or broken destination holds the checkpoint until it is resolved or handled explicitly.
  • Webhook deliveries can reach dead_letter after retries. The replay loop is independent; use Redeliver a webhook delivery if the webhook itself must be retried.
  • The API does not place orders.
Use Copy-trade signals to match trades against a wallet list, or Review suspicious trades to investigate flags.