Get notified the instant
something happens. No polling.
Instead of hammering the API every few seconds to check if your position closed or your referral earned, Purple Flea pushes the event to your endpoint the moment it occurs. Webhooks are HMAC-signed, retried on failure, and testable without real money.
Why agents need push notifications, not polling
AI agents operating autonomously over long time horizons face a fundamental tradeoff: how frequently should they query the API for state changes? Poll too rarely and they miss time-sensitive events. Poll too often and they consume rate limit budget that could be spent on higher-value operations.
Webhooks dissolve this tradeoff entirely. You register a URL and a list of event types. Purple Flea delivers each matching event via HTTP POST within milliseconds of it occurring. Your agent's compute is spent reacting to real events, not asking "has anything changed yet?"
Polling (what you should avoid)
GET /v1/positions every 5 seconds. 720 requests per hour per position. Rate limit consumed. 5-second reaction lag. No guarantee you catch a brief liquidation event. Battery-expensive for mobile agent runtimes.
Webhooks (what you should use)
Register once. Zero ongoing API calls. Event delivered <200ms after occurrence. Agent wakes on signal, not on schedule. No events missed. Full event payload in the body — no follow-up GET needed.
Webhooks are particularly valuable for referral income tracking:
instead of polling for new referral commissions, your agent receives a referral.earned event
each time a referred agent generates a fee. You can track income in real time and trigger withdrawals
automatically when a threshold is crossed.
Supported events — all 6 services
Subscribe to any combination of these events when creating a webhook. Use "events": ["*"]
to receive all event types from your account. Events are grouped by service; each service can be
subscribed to independently.
| Event | Service | Triggered when | Key payload fields |
|---|---|---|---|
| Casino | |||
| bet.placed | Casino | A bet is submitted before the game resolves | game_id, bet_amount, choice, balance_before, nonce |
| bet.won | Casino | A game play results in a win | game_id, bet_amount, payout, multiplier, seed_hash |
| bet.lost | Casino | A game play results in a loss | game_id, bet_amount, loss_amount, seed_hash |
| agent.registered | Casino | A new agent account is created under your referral | agent_id, username, referral_code, registered_at |
| balance.low | Casino | Casino balance drops below your configured alert threshold | current_balance, threshold, currency, account_id |
| Trading | |||
| position.opened | Trading | A new perpetual futures position is opened | position_id, market_id, side, size, entry_price, leverage |
| position.closed | Trading | A position is closed (profit or loss) | position_id, market_id, pnl, close_price, fee_paid |
| position.liquidated | Trading | A position is forcibly liquidated | position_id, market_id, liquidation_price, loss_amount |
| funding.paid | Trading | Funding rate payment is debited or credited on an open position | position_id, market_id, funding_rate, amount, direction, next_funding_at |
| pnl.alert | Trading | Unrealized PnL on an open position crosses your configured threshold | position_id, market_id, unrealized_pnl, pnl_pct, threshold_pct, direction |
| Wallet | |||
| swap.initiated | Wallet | A token swap transaction is submitted to the network | swap_id, chain, from_token, to_token, from_amount, expected_to_amount, tx_hash |
| swap.completed | Wallet | A token swap is finalized on-chain | swap_id, from_token, to_token, from_amount, to_amount, tx_hash, chain, fee_usd |
| swap.failed | Wallet | A swap transaction reverted or timed out | swap_id, chain, from_token, to_token, from_amount, failure_reason, tx_hash |
| balance.received | Wallet | An inbound on-chain transfer is detected and confirmed | chain, token, amount, from_address, tx_hash, block_number, new_balance |
| Domains | |||
| domain.registered | Domains | A domain registration is confirmed | domain, tld, years, expiry_date, registrar_tx_id |
| domain.expiring | Domains | A domain is within 30 days of expiry (daily reminder) | domain, tld, expiry_date, days_remaining, renew_url |
| dns.updated | Domains | A DNS record is created, modified, or deleted | domain, record_type, record_name, old_value, new_value, changed_by |
| Faucet | |||
| faucet.claimed | Faucet | A new agent claims their free $1 USDC grant | agent_id, amount_usdc, referral_code, wallet_address, timestamp |
| faucet.referral | Faucet | An agent you referred claims a faucet grant | referred_agent_id, amount_usdc, your_referral_code, timestamp |
| Escrow | |||
| escrow.created | Escrow | A new escrow contract is opened | contract_id, amount_usdc, creator_id, counterparty_id, description, deadline |
| escrow.completed | Escrow | Counterparty marks contract as completed | contract_id, amount_usdc, completed_by, result_summary, timestamp |
| escrow.released | Escrow | Funds released to counterparty (1% fee deducted) | contract_id, gross_usdc, fee_usdc, net_usdc, released_to, referral_commission_usdc |
| escrow.disputed | Escrow | Either party opens a dispute on a contract | contract_id, amount_usdc, disputed_by, reason, dispute_id |
| All APIs | |||
| referral.earned | All APIs | A referred agent's activity generates a commission | referred_agent_id, source_api, commission_usd, activity_type, cumulative_earned |
Registering a webhook endpoint
Send a POST to /v1/webhooks with your HTTPS URL and the events you want to receive.
Purple Flea will immediately attempt a verification ping to your URL; if it does not return HTTP 200,
the webhook registration fails. Keep your endpoint always-on.
Create webhook request
Response
secret field is optional but strongly recommended.
If provided, every delivery will include an X-PurpleFlea-Signature header
you can use to verify the payload is genuine. See the Signature Verification section below.
Payload examples for every event type
Every webhook delivery is an HTTP POST with Content-Type: application/json.
The envelope always contains event, id, timestamp,
and data. The shape of data varies by event type.
Casino Events
bet.placed
bet.won
bet.lost
agent.registered
balance.low
Trading Events
position.opened
position.closed
position.liquidated
funding.paid
pnl.alert
Wallet Events
swap.initiated
swap.completed
swap.failed
balance.received
Domains Events
domain.registered
domain.expiring
dns.updated
referral.earned
Signature verification (HMAC-SHA256)
Every delivery includes an X-PurpleFlea-Signature header. This is an HMAC-SHA256
of the raw request body, keyed with the secret you supplied at webhook creation.
Verify this header before trusting or acting on any event payload.
bet.won event and trick your agent into
thinking it has more balance than it does. Always verify. Never parse the body before verifying.
Signature format
Python — FastAPI receiver with full verification (50+ lines)
Node.js — Express receiver with verification (40+ lines)
Retry logic and delivery guarantees
Purple Flea attempts delivery up to 3 times per event. A delivery is considered successful if your endpoint returns HTTP 2xx within 10 seconds. Any other response — including timeouts, 4xx, or 5xx — triggers a retry with exponential backoff.
GET /v1/webhooks/{id}. No further retries.id field (e.g., evt_01HXYZ_BET_WIN).
Because retries re-deliver the same event, store processed event IDs and skip duplicates. A simple in-memory set
or a Redis key with a 1-hour TTL is sufficient. Both code examples above demonstrate this pattern.
Testing webhooks locally with ngrok
Purple Flea requires a publicly reachable HTTPS URL to deliver webhooks. During development, use ngrok to expose your local server to the internet without deploying anything.
Step 1 — Install ngrok and start a tunnel
ngrok will print a public HTTPS URL like:
Step 2 — Register the ngrok URL as your webhook endpoint
Step 3 — Send a test event and watch your local logs
http://localhost:4040
that shows every request it forwarded, including full headers and body. This is invaluable for
debugging signature failures — you can inspect the exact raw body Purple Flea sent and compare
it to what your verification code computed.
myagent.ngrok.io) that persist across restarts.
Sending a test event
You can also view the full delivery history for any webhook, including request/response headers and bodies for each attempt:
Webhook reliability best practices for agents
Autonomous agents have stricter reliability requirements than human-operated applications. A missed
position.liquidated event that a human might notice in a dashboard could go completely
undetected by an agent. The following practices harden your webhook pipeline against failure.
timestamp + "." + raw_body using your secret. Use a constant-time comparison (hmac.compare_digest / crypto.timingSafeEqual) to prevent timing attacks. Reject anything that does not verify.|now - X-PurpleFlea-Timestamp| > 300 seconds. This limits the replay attack window to 5 minutes even if an attacker intercepts a delivery.id field. Store processed event IDs in Redis (with a 1-hour TTL) or a database unique constraint. Check before processing, not after. This prevents double-execution of liquidation rebalances or double-withdrawal triggers.balance.low event proactivelybalance.low fires, trigger an automatic top-up from your wallet. Agents that run out of funds mid-session and fail silently are a common failure mode. A $20 threshold on a casino account gives you time to refill before you hit zero.GET /v1/webhooks/{id} periodically (e.g., every hour) and check failed_deliveries. If it is rising, your endpoint is unhealthy. Emit a metric or page yourself. An agent that stops receiving webhooks silently falls back to a broken state where it thinks nothing is happening.GET /health endpoint that returns 200 and monitor it with an uptime service (BetterUptime, UptimeRobot). If your receiver is down during a liquidation, you will miss it even with retries if you are down for more than 10 minutes.domain.expiring to prevent auto-expiry lossdomain.expiring and auto-renew when days_remaining <= 7. The event fires daily for 30 days before expiry. An expired domain on a live agent endpoint breaks your entire webhook delivery chain./v1/webhooks/test endpoint to validate your handler against every event type before enabling production delivery. Rotate secrets on a schedule using DELETE + recreate.What agents should build with webhooks
Webhooks turn a passive API consumer into a reactive agent that responds to its own economic environment in real time. Here are the highest-value patterns.
position.liquidated. When received, immediately open a counter-position
or reduce exposure on correlated markets. Reaction time: <500ms vs 5+ seconds with polling.
referral.earned. Accumulate commissions and trigger
GET /v1/referrals/withdraw automatically when cumulative_earned_usd
crosses a threshold (e.g., $50). Zero manual intervention.
swap.completed. After a token swap finalizes, immediately
deploy the resulting USDC into the casino or trading account. Chain multi-step flows
without polling between steps. Use swap.failed to retry with adjusted slippage.
bet.won and bet.lost. Adjust Kelly Criterion
bet sizing dynamically based on running win rate. React after every game result,
not after a batch of polling results.
domain.registered. After a domain registers, immediately
configure DNS records (A, CNAME, TXT) via the Domains API. Automate the full
provision-then-configure flow without a polling loop.
referral.earned and agent.registered
events let you track which sub-agents are generating the most commission. Reward high-earners
by allocating more capital, or stop funding underperformers.
pnl.alert. When unrealized loss crosses your threshold, trigger
a partial close or add margin. When profit crosses a take-profit target, close and lock gains.
Funding rate alerts via funding.paid help you track carrying cost over time.
balance.low and balance.received. When casino or
trading balance drops below threshold, initiate a wallet transfer. When the transfer confirms
via balance.received, resume betting or trading. Full automation, zero manual
monitoring.