A bet placement API takes a bet your code sends, places it in a bookmaker account you hold and reports back what happened. Before it touches real money, check six things: the timeout path, reconciliation with the bookmaker's records, the handling of part-accepted and refused bets, callback signatures, a full run on a demo key, and who can reach the key.
These checks are about bet execution, getting a bet accepted at a price you will take, and they apply to any API that bets in your own accounts, whoever built it. Placing bets programmatically fails in ways a price feed cannot: a lost reply can become two bets, and a bet can come back smaller than you sent it. Among the betting tools in Australia, this is the one where a software mistake becomes a bet.
A timeout is not a failure: duplicates and idempotency
A timeout means no answer arrived in time. It does not mean the bet failed: the bookmaker may have accepted it a moment after your code stopped waiting. Code that resends on a timeout can place the same bet twice, and code that retries in a loop can place it many times. With illustrative figures, a $40 bet at $2.60 resent every 5 seconds for 30 seconds is 7 sends:
| If every send is accepted | One bet, as intended | Seven bets, after blind retries |
|---|---|---|
| Staked | $40 | 7 x $40 = $280 |
| Lost if it loses | $40 | $280 |
| Profit if it wins | 40 x (2.60 - 1) = $64 | 7 x $64 = $448 |
The bigger win is no consolation: the extra $448 - $64 = $384 is profit on $240 of stake your plan never allowed, and the same retries make every loss seven times as large.
The standard defence is an idempotency reference: a unique id your code creates for each bet decision before the first send, stores, and sends again unchanged with any resend. An API that supports one treats a second send with the same reference as the same bet and returns the first result instead of placing it again. Whether an API supports this is something its documentation has to say plainly. If it does not, treat every send as a new bet.
After a timeout, then:
- Mark the bet as unknown, and send nothing more for that selection.
- Ask the API for the bet's status, by your reference or the id it returned, if it offers a status call.
- Check the bookmaker's own bet history for a bet with that selection, stake and time.
- If the bet is there, record it as placed. If it is not, and the API's stated window for a late result has passed, decide again at the current price, as a new bet with a new reference.
Reconcile every bet with the bookmaker's bet history
Your records and the bookmaker's bet history should agree on every bet: the bookmaker's bet id, the selection, the price taken, the stake accepted, the time and the status. Match on the bet id first, and where there is none, on selection and stake within a short window such as two minutes. Treat any mismatch you cannot explain as a reason to stop. With illustrative records from one afternoon:
| Your record | Bookmaker's bet history | What it means | What to do |
|---|---|---|---|
| Placed, $60 at $2.75 | $60 at $2.75 | A match | Nothing |
| Placed, $60 at $2.75 | $60 at $2.90 | The bet went on above your floor, and your record kept the floor you sent | Record the price taken from the receipt, not the price sent |
| Placed, $120 at $1.95 | $45 at $1.95 | Partly accepted, recorded as full | Correct the stake: your exposure was overstated by $75 |
| Refused | $35 at $4.40, 2:41 pm | A bet you believe failed is open | Stop: a resend would have doubled it |
| No record | $35 at $8.00, 3:12 pm | A bet your code never sent, or never recorded | Stop: look for a duplicate, then for a key in the wrong hands |
Stopping means every session at once, which is the job of a kill switch, and nothing restarts until each mismatch has a cause.
Check monthly totals as well. Measure 7 of the National Consumer Protection Framework, in force since 31 July 2022, requires online wagering providers to send active customers a monthly activity statement, which lists the number of bets and the net result among other figures. For example, if your records show 212 bets and a net result of -$84.50 for the month, and the statement shows 214 bets and -$124.50, then two bets and $40 of losses are missing from your code's view. Find them before you bet again.
Partial acceptance, price changes and refusals
A bet sent is not a bet placed. Besides taking the whole stake at your price, a bookmaker can take part of the stake, take it at another price, or refuse it. The market may be suspended, the stake may be over its limit for your account, or the price may have moved. The price can shift in the seconds between your decision and the bet's arrival, which is betting latency at work, and the price floor you send with each bet decides whether a moved price is still acceptable.
Partial acceptance is written into at least one racing body's rules. Since 1 July 2025, Racing Queensland's conditions have made off-course operators accept part of a fixed-odds bet on a Queensland race, up to the minimum bet limit, instead of turning the whole bet away. The same update lets punters use automation to select a market and add it to the bet slip, but says this change does not oblige an operator to accept a bet completed by automation. Minimum bet limits explained covers the rule itself.
With illustrative figures, your code sends $150 with a $3.20 floor, and the bookmaker accepts $60 at $3.25:
| How your code handles it | Stake in your records | Return if it wins | What goes wrong |
|---|---|---|---|
| Records what was accepted | $60 | 60 x 3.25 = $195.00 | Nothing |
| Records what it sent | $150 | 150 x 3.25 = $487.50 | Your records overstate the return by $292.50 |
| Resends $150 to finish the job | Up to $60 + $150 = $210 | Up to 210 x 3.25 = $682.50 | Up to $210 at risk, against the $150 you planned |
Record what was accepted, never what was sent, and never resend the remainder automatically. If you still want more on, that is a new decision at the current price, with its own reference and inside your limits.
On the way back, each outcome looks different. A result might carry fields like these (illustrative names, not any one provider's format):
| Field | Placed in full | Partly accepted | Refused |
|---|---|---|---|
| Status | Placed | Placed | Refused |
| Stake sent | $150 | $150 | $150 |
| Stake accepted | $150 | $60 | $0 |
| Price taken | $3.25 | $3.25 | None |
| Bookmaker bet id | Present | Present | None |
| Reason | None | Stake limit | Price below floor |
Read the accepted stake and the bookmaker's bet id, never the status alone: a partly accepted bet and a full one can carry the same status word.
Results by signed callback or by polling
Results come back one of two ways. With polling, your code asks the API for each bet's status until it is final or a deadline passes. With a callback, often called a webhook, the API sends the result to a web address you run as soon as it is ready.
Polling is simple and survives your own server restarting, but every check is a request against your limits. Space the checks out as the bet ages, and when the deadline passes with no final status, the bet is unknown: follow the timeout steps above.
A callback is quicker and cheaper, but your callback address is not a secret, and anyone who finds it can post to it. A forged "refused" could make your code resend a bet that was placed, and a forged "placed" could hide one that failed. So check every callback before you trust it:
- The API signs each callback, usually with an HMAC: a code computed from the exact body and a secret that only you and the API hold.
- Your server computes the same code from the raw body it received and compares the two.
- If they differ, or the signature is missing, discard the callback and record nothing.
- If the same result arrives twice, act on it once, and expect results to arrive out of order.
Keep a slow poll running behind the callbacks. If your server is down when a result is sent, polling is how you find out what happened.
Demo keys and a dry run before live money
Run the whole flow before any real stake: send bets to a demo key, or against sample responses, that cover every result your code must handle, the bad ones included. A dry run that only ever sees a successful bet tests nothing.
| Scenario | What your code must do | It passes if |
|---|---|---|
| Placed in full | Record the stake and the price taken | The record matches the sample receipt |
| Partly accepted | Record the accepted stake only | Nothing resends the remainder |
| Refused below the floor | Record the refusal | No retry at a lower price |
| Timeout | Mark the bet unknown and check | No second send |
| Callback with a bad signature | Discard it | Nothing is recorded |
| The same callback twice | Act once | One record, not two |
Then go live in steps: the smallest stake the bookmaker accepts, a maximum stake per bet, a cap on the day's total, and a floor on every bet. Change any of those limits only after a week in which every bet reconciled, and never beyond what you set out to risk.
API keys: where they live and who can send bets
Anyone holding your API key can send bets into your accounts, so treat it like the passwords to those accounts.
| Keep the key | Never put the key |
|---|---|
| In server-side code that only you run | In a web page or a browser extension, where anyone can read it |
| In an environment variable on that server | In a repository, private ones included, because the history keeps it after you delete it |
| In a password manager, for safekeeping | In a shared document, a chat message or a screenshot |
If a key leaks, replace it at once, stop every session that accepts bets from it, and check each bookmaker's bet history for bets you did not send. A bet in that history with no record on your side, the last row of the reconciliation table, can be the first sign.
Volume, bookmaker terms and when not to automate
Automation can bet far more, far faster, than by hand, and an API removes the last pause before each bet. Set a deposit limit with each bookmaker before your code places its first bet. Under measure 6 of the National Consumer Protection Framework every online wagering provider must offer deposit limits, and lowering one takes effect straight away while raising one takes 7 days. Code can only bet what is in the account, so a deposit limit caps the new money a bug can lose.
Bookmakers' terms decide whether automated bets are welcome, and many restrict automated betting and third-party access. Under those terms an account can have its stakes cut, its bets voided or be closed, and that risk sits with you. Whether automated betting is lawful where you live is a different question, and nothing here is legal advice.
If you place a handful of bets a week, chosen by eye, placing them by hand in your own account is simpler and safer than any API. A placement API is worth its complexity when your rules are already code and you are ready to reconcile every bet it places.
B337's own placement API is the Execution API, which sends racing and sports bets from your code to sessions running on your computer, in accounts you hold. That computer has to be on, awake and online for a bet to go on. The betting API page sets out its request format, result flow and limits.
Risk: Betting involves risk. Code can place bets faster than you can notice a fault, a bet placed exactly as intended can still lose, and many bookmakers restrict automated betting in their terms. See responsible gambling for limits and support.
For free and confidential support call 1800 858 858 or visit gamblinghelponline.org.au.