Gareth Wilson Gareth Wilson

Guide to Live Tennis API Webhooks: Features and Best Practices

Published


Live Tennis API webhooks push live tennis data to your servers as it changes: every accepted score update, every played point, and every break point as it arises and resolves. If you build scoreboards, betting tools or broadcast graphics on Live Tennis API, webhooks are an alternative to holding a WebSocket open or polling the scores endpoints.

This guide covers how Live Tennis API webhooks are registered and signed, the frames they carry, the delivery rules that make them unusual, and the practices that keep a receiver from missing points.

What are Live Tennis API webhooks?

A Live Tennis API webhook is an HTTPS URL registered through the API. It receives the same frames as the push feed, one POST per frame. Webhooks are an ULTRA plan feature and need a direct API key: marketplace keys can't register them.

Each delivery has three headers. X-LTAPI-Signature holds sha256= and the hex HMAC-SHA256 of the raw body, keyed with the webhook's secret. X-LTAPI-Event names the frame type. X-LTAPI-Timestamp is the send time in Unix seconds, and it is not part of the signature.

What sets these webhooks apart is the delivery model. Live Tennis API makes one attempt per frame, with a timeout of about three seconds, and never retries or replays. Score frames recover on their own because each one is the full current score. Point frames don't, so a receiver needs a catch-up path.

Live Tennis API webhook features

FeatureDetails
ConfigurationAPI only: POST, GET and DELETE on /api/public/v1/webhooks
RequirementsULTRA plan and a direct (not marketplace) API key
Limit3 webhooks per key
Frame typeThe X-LTAPI-Event header
Signature headerX-LTAPI-Signature: sha256=<hex>
SchemeHMAC-SHA256, hex digest
Signed contentThe raw request body only
SecretOne per webhook, shown only in the 201 registration response
TimestampX-LTAPI-Timestamp, Unix seconds. Not signed
DeliveryAt-most-once: one attempt per frame, no retries, no replay
TimeoutAbout 3 seconds. Redirects are not followed
Auto-disableAfter 25 consecutive failures
Source IPsNot published

Common events

X-LTAPI-Event carries one of four frame types:

FrameSent whenMissed delivery
scoreA live score commit is accepted. The frame is the complete current scoreSelf-corrects on the next commit
pointA point is played. The frame carries one point, with a per-match seqLost unless you fetch it again
break_pointA break point arises, with server, returner and break_pointsLost
break_point_resultA break point resolves, with outcome of held or brokenLost

The registration body's events array decides what a webhook receives. It defaults to ["score"]. The API spec lists score, break_point, point, status and stoppages as accepted values, where break_point covers both break point frames and point is sent only where the point surface is enabled and the match has pbp_coverage: "point". The webhook documentation describes only the four frame types above, so log the X-LTAPI-Event value of anything else before relying on it.

A point frame carries type, match_id, published_at, pbp_coverage, quality and a point object. Inside it, seq is per-match, monotonic and never skips a value, which makes it the deduplication and resume key across webhooks, the WebSocket and the REST catch-up endpoint.

Setting up Live Tennis API webhooks

Register a webhook with your API key:

curl -X POST "https://api.livetennisapi.com/api/public/v1/webhooks" \
  -H "X-API-Key: $LIVE_TENNIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/webhooks/live-tennis-api", "events": ["score", "point"]}'

The 201 response includes the webhook's id and its secret. Store the secret straight away, for example as LIVE_TENNIS_API_WEBHOOK_SECRET: this is the only time it is shown, and GET /webhooks never returns it. A fourth webhook on the same key returns 409 webhook_limit, so delete one first with DELETE /webhooks/{webhookId}.

The URL must be HTTPS and publicly routable, and it must answer directly: redirects are disabled, so a URL that redirects from http to https, or adds a trailing slash, fails every delivery.

Securing Live Tennis API webhooks

Read X-LTAPI-Signature, require and strip sha256=, compute an HMAC-SHA256 of the raw body with the webhook secret, and compare in constant time.

const crypto = require('crypto');
const express = require('express');

function verifyLiveTennisSignature(rawBody, header, secret) {
  const match = /^sha256=([0-9a-f]{64})$/i.exec(typeof header === 'string' ? header : '');
  if (!match || !secret) return false; // check the hex shape before Buffer.from(x, 'hex')

  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
  const received = Buffer.from(match[1], 'hex');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

const app = express();

app.post('/webhooks/live-tennis-api', express.raw({ type: '*/*' }), (req, res) => {
  const secret = process.env.LIVE_TENNIS_API_WEBHOOK_SECRET;
  if (!secret) return res.sendStatus(500); // fail closed

  if (!verifyLiveTennisSignature(req.body, req.get('x-ltapi-signature'), secret)) {
    return res.sendStatus(401);
  }

  const frame = JSON.parse(req.body.toString('utf8'));
  const frame_type = frame.type || req.get('x-ltapi-event');
  // Queue the frame and return straight away: the timeout is about 3 seconds.
  res.sendStatus(200);
});

The same check in Python:

import hashlib
import hmac


def verify_live_tennis_signature(raw_body: bytes, header, secret: str) -> bool:
    if not header or not secret or not header.startswith("sha256="):
        return False
    expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
    # Compare bytes so a non-ASCII header fails verification instead of raising.
    received = header[len("sha256="):].lower().encode("utf-8")
    return hmac.compare_digest(received, expected.encode("utf-8"))

Live Tennis API suggests rejecting stale replays using X-LTAPI-Timestamp. Because that header is not signed, anyone replaying a captured request can change it, so it is a weak check at best. Deduplicate point frames on seq instead.

Make Live Tennis API webhooks production-ready. Hookdeck Event Gateway answers each delivery as soon as it arrives, verifies the X-LTAPI-Signature header, and queues every score and point frame for your service, so a slow handler never misses the three-second window.

Live Tennis API webhook limitations and pain points

At-most-once delivery

The Problem: A frame that your endpoint doesn't accept in time is gone.

Why It Happens: Live Tennis API makes a single attempt per frame with a timeout of about three seconds, and has no retries or replay. A deploy, a cold start or a slow database write is enough to lose a frame.

Workarounds:

  • Acknowledge first and process afterwards, so the response never depends on your own work.
  • For point frames, track the last seq per match and fetch gaps from GET /matches/{matchId}/points?after_seq=.
  • For score frames, wait for the next commit or read GET /matches/{matchId}/score.

How Hookdeck Can Help: Hookdeck accepts each delivery straight away and stores it, then delivers it to your service with automatic retries. Your own downtime then delays frames instead of losing them, as long as Hookdeck can be reached.

25 failures and the webhook switches off

The Problem: Deliveries stop, and nothing comes back until you register the webhook again.

Why It Happens: After 25 consecutive failures, Live Tennis API sets enabled to false and records last_error. There is no re-enable call: you delete the webhook and register a new one, which also means a new secret. During a busy day of matches, 25 failures can happen in seconds.

Workarounds:

  • Poll GET /webhooks and alert when enabled is false or consecutive_failures climbs.
  • Script re-registration so you can restore the webhook and deploy the new secret quickly.

How Hookdeck Can Help: With Hookdeck in front, Live Tennis API delivers to Hookdeck rather than to your service, so an outage on your side doesn't count towards the 25 failures. If you do re-register, you update the secret on one Hookdeck source.

The timestamp isn't signed

The Problem: A replay check built on X-LTAPI-Timestamp can be bypassed.

Why It Happens: The signature covers only the body. The timestamp is a separate, unsigned header.

Workarounds:

  • Deduplicate on seq for point frames, and treat score frames as idempotent state.
  • Keep the endpoint on HTTPS.

How Hookdeck Can Help: Hookdeck's deduplication can drop repeated frames based on body fields you choose, such as match_id with point.seq.

Best practices

Verify against the raw body

The HMAC covers the exact bytes sent. Use express.raw() in Express, await request.text() in a Next.js route handler and await request.body() in FastAPI, and parse only after the check passes.

Treat score frames as state and point frames as events

A score frame replaces whatever you held before, so apply the latest one and move on. A point frame adds to a sequence, so store it by match_id and seq and fill gaps from the points endpoint.

Respond in well under three seconds

Do nothing but verify and enqueue before you return 200. See why to process webhooks asynchronously.

Keep the URL redirect-free

Register the exact URL that serves the handler, with the right scheme, host and path. Redirects are not followed.

Watch webhook health

Read last_delivery_at, consecutive_failures and last_error from GET /webhooks and alert before the 25-failure limit is reached.

Conclusion

Live Tennis API signs each frame with X-LTAPI-Signature: sha256= and a hex HMAC-SHA256 of the raw body. Store the secret from the registration response, verify against the raw bytes, answer within three seconds, and build a catch-up path for point frames, because delivery is at-most-once and 25 failures in a row disable the webhook.

Hookdeck Event Gateway sits in front of your receiver, checks every signature, and holds each frame until your service has processed it.

Get started with Hookdeck for free and handle Live Tennis API webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.