Football webhooks: stop polling for goals
Most football APIs make you poll. We push match events to your server the second they land. Register an endpoint, handle the retry schedule, and cut hundreds of wasted requests per match.
GOAL API· Engineering

Polling burns your quota on nothing
A polling loop asks the same question again and again. Most answers come back identical.
Run one request every 10 seconds across a 2 hour match. You spend 720 requests to catch 3 goals. The other 717 requests told you nothing changed.
Webhooks reverse the direction. You register a URL once. We POST to your server the moment a match event lands.
Events you receive
match.started: the match kicked offgoal.scored: the score went up, fires once per goalscore.changed: the score moved without a goal, because the provider corrected an earlier mistakematch.finished: the match ended, including after extra time or penaltiesmatch.status_changed: any status transition, such as half time or postponed
Treat goal.scored and score.changed differently. A correction is not a goal. Firing a "GOAL" push notification for a scoring correction annoys your users and teaches them to mute you.
Register an endpoint
curl -X POST https://api.goal-api.com/v1/auth/webhook-endpoints \
-H "Authorization: Bearer $GOAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/goal-api",
"events": ["goal.scored", "match.started", "match.finished"]
}'
The response returns your signing secret one time. Store the secret before you close the connection. Lose the secret and you rotate.
Answer in under 8 seconds
We time out after 8 seconds.
Return 2xx first. Do your work after.
app.post("/webhooks/goal-api", express.raw({ type: "application/json" }), (req, res) => {
const event = JSON.parse(req.body);
// Answer immediately, then process off the request path.
res.sendStatus(200);
queue.push(event);
});
A slow handler becomes a failed delivery. A failed delivery becomes a retry. Retries multiply your load at the worst possible moment, when goals are arriving.
Retries follow a fixed schedule
Five attempts across roughly half a day: 1 minute, 5 minutes, 25 minutes, 2 hours, 10 hours.
Anything outside 2xx triggers the next attempt.
Make your handler idempotent. A timeout on our side after your database write means you receive the same event twice. Key your processing on the event id and ignore duplicates.
Debug with the delivery log
curl https://api.goal-api.com/v1/auth/webhook-endpoints/ENDPOINT_ID/deliveries \
-H "Authorization: Bearer $GOAL_API_KEY"
Recent attempts come back with response status codes. Start there when events go missing. Most reports of "webhooks are broken" turn out to be a 500 from the receiving app.
Plan limits
| Plan | Price | Endpoints |
|---|---|---|
| Free | 0 | 0 |
| Pro | 19 | 3 |
| Ultra | 29 | 5 |
| Mega | 45 | 10 |
Each delivery counts as one request against your daily quota. A push we send on your behalf costs the same as a request you send us.
Before you go live
Verify the signature on every delivery. Your endpoint URL is not a secret. Anyone who learns the URL posts fake goals into your app until you check signatures.


