18+ Only  |  Gambling can be addictive — please gamble responsibly  |  Gambling Help: 1800 858 858  |  GambleAware

API reference / Webhooks

POST /v1/webhooks

Create Webhook

Subscribe an HTTPS endpoint to signed event pushes. Events that fire on their own: `race.odds_open` (a race's first bookmaker prices landed), `race.result` (a race's result went final, from 2026-10-13) and `arb.opportunity` (a cross-book arb opened). `odds.change` is the event POST /v1/webhooks/{id}/test sends and nothing else does. An unknown event name is a 422 that lists the events that fire, and nothing is created; `market.suspend`, withdrawn on 2026-10-13 because it never fired, is refused the same way. Each delivery is a POST of the JSON payload with `X-PuntersEdge-Event` naming the event and `X-Webhook-Signature: sha256=<hex>`, the HMAC-SHA256 of the raw body keyed with the `secret` in this response. The secret is returned once, here (POST /v1/webhooks/{id}/rotate-secret issues a new one when the delivery queue is enabled). Delivery is at-least-once: the same event can arrive more than once, so deduplicate on `event_id` (in the body, and sent as the `X-PuntersEdge-Id` and `Idempotency-Key` headers). There is no ordering guarantee between events. Each delivery carries `X-PuntersEdge-Timestamp`, `X-PuntersEdge-Attempt` and two signatures: `X-Webhook-Signature: sha256=<hex>` (HMAC-SHA256 of the raw body with your secret) and `X-PuntersEdge-Signature: t=<unix seconds>,v1=<hex>` (HMAC-SHA256 of `<t>.<raw body>`; refuse a `t` more than 5 minutes from now to block replays). Any 2xx answer is success. A 5xx, 408, 429, timeout or connection failure is retried after 1 min, 5 min, 30 min, 2 h, 6 h (6 tries in all, about 8.5 hours), honouring `Retry-After` up to the next step; any other answer is final. After 10 consecutive undeliverable events, or a day of continuous failure, the subscription is paused and the owner is emailed; POST /v1/webhooks/{id}/resume restarts it with the same secret, and POST /v1/webhooks/{id}/replay re-sends what was missed. The delivery log returns the newest 50 rows unless `limit` says otherwise.

Requires X-API-Key

Request

curl -X POST 'https://api.puntersedge.online/v1/webhooks' \
  -H 'X-API-Key: YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com/hooks/puntersedge", "events": ["arb.opportunity"], "min_edge_pct": 1.5, "sports": ["nrl", "afl"]}'

Parameters

NameIn TypeRequired Description
url body string yes HTTPS endpoint that receives the POST, on port 443 or 8443. Plain http://, a host that does not resolve, and a host that resolves to a private, loopback, link-local or other non-public address are rejected with 422. At most 5 subscriptions per API key (409 beyond that).
events body array no Events to subscribe to. Three events have live producers: `arb.opportunity` (a cross-book arb opened), `race.odds_open` and `race.result`. `race.odds_open`: the first bookmaker prices for a race just landed — fires once per race, so you can fetch the card on push instead of schedule-polling. Since the early-market lanes of 2026-09-01 it fires HOURS ahead, not minutes: measured over the 48h to 2026-09-03 11:00 UTC, the first price landed a median 10.1h before the jump on AU thoroughbreds, 5.3h on greyhounds, 6.8h on harness - typically overnight or early morning for the day's card, from one or two early books; the full board fills inside about an hour of the jump. `race.result` (from 2026-10-13): a race's result just went `final` — fires once per race, carrying the race (`race_id`, `result_id`, venue, race number, start, country, category), the placings ({position, name, number, horse_ref}), the `dividends` where the settling source declares them, and `source`. `race_id` is the id race.odds_open and /v1/racing/next-to-go carried for the race, and is null on the rare result we could not link to a priced race (10 of 2,038 final results in the 7 days to 2026-10-12); `result_id` is always set. A result goes final once its placings have been stable for 30 minutes, and the event follows within about five minutes of that: measured over the 3 days to 2026-10-12, results went final a median 36 minutes after the advertised start on AU and NZ races (p90 39), 38 on British and Irish thoroughbreds, and about 4 on British and Irish greyhounds, whose source publishes the result already final. It is the same row /v1/racing/results serves, so settle on it exactly as you would on that endpoint. `odds.change` is delivered solely by POST /v1/webhooks/{id}/test. `market.suspend` was withdrawn on 2026-10-13 — it never had a producer — and is now refused with 422.
min_edge_pct body number no Only deliver arb.opportunity when the theoretical edge is at least this percentage. Omit for every opportunity.
sports body array no Only deliver events for these sports. Sport keys as returned by GET /v1/sports; racing events (arbs, race.odds_open and race.result) arrive as racing_horse, racing_greyhound or racing_harness. Omit for all sports.

Responses

Status codes: 200, 401, 402, 403, 409, 422, 429, 500. Response bodies are JSON; the full schema is in /openapi.json.

Example response

200 application/json Field names and types are as the API returns them; values are a real sample, trimmed to a few items.

{
  "id": "wh_7c1d2e9a4b3f",
  "url": "https://example.com/hooks/puntersedge",
  "events": [
    "arb.opportunity",
    "race.odds_open",
    "race.result"
  ],
  "min_edge_pct": 1.5,
  "sports": [
    "racing_horse",
    "racing_greyhound",
    "nrl"
  ],
  "is_active": true,
  "created_at": "2026-09-07T00:52:10",
  "last_delivery_at": null,
  "failure_count": 0,
  "secret": "whsec_EXAMPLE_ONLY_shown_once_at_creation",
  "delivery_entitled": true,
  "delivery_paused_reason": null
}

Related endpoints

Try it against live data

The free tier needs no credit card, and the sandbox endpoints need no key at all.

Get a free API key Quickstart
This site contains wagering-related analysis and is intended for Australian users aged 18+. Gambling involves risk. Please gamble responsibly.