Skip to content
British Powerlifting — Tools Portal home

Developers & partners

Membership check API

A free JSON API that confirms whether someone is a current British Powerlifting member — for example to give BP members a discount at your gym, shop, event or online checkout. No sign-up or API key is needed.

It may only be used for the authorised uses, under the terms of use.

Download as Markdown for AI tools All data feeds & APIs

Quick start

Send at least two of a person's full name, email address and membership number:

curl
curl -sS -X POST 'https://tools.britishpowerlifting.org/api/v1/membership-check' \
  -H 'Content-Type: application/json' \
  -d '{"first_name": "Jane", "last_name": "Smith", "membership_number": "GB123456"}'

You get back one of three answers, always with HTTP 200:

Active member

json
{"status": "active",
 "membership_expires_on": "2027-03-31",
 "matched_on": ["name", "membership_number"],
 "data_as_of": "2026-10-05T01:14:09Z",
 "data_may_be_stale": false,
 "checked_at": "2026-10-05T09:30:00Z"}

Expired

json
{"status": "expired",
 "membership_expires_on": "2026-08-31",
 "matched_on": ["name", "membership_number"],
 "data_as_of": "2026-10-05T01:14:09Z",
 "data_may_be_stale": false,
 "checked_at": "2026-10-05T09:30:00Z"}

Couldn't confirm

json
{"status": "not_found",
 "membership_expires_on": null,
 "matched_on": [],
 "data_as_of": "2026-10-05T01:14:09Z",
 "data_may_be_stale": false,
 "checked_at": "2026-10-05T09:30:00Z"}

Version 1 is stable: we'll only ever add response fields, never remove or rename them, so ignore fields you don't recognise. A breaking change would get a new /api/v2/membership-check address, with notice. The old address, /membership-check/api/v1/check, still works but is deprecated.

Who can use this

You may use the membership checker and its API only to confirm that a person holds a current British Powerlifting membership, for one of these purposes:

  • Running or organising a competition or event, to check that entrants are current members.
  • A club or affiliated organisation confirming that its members or athletes hold British Powerlifting membership.
  • A promotion, discount or benefit aimed at the British Powerlifting community, to confirm that someone qualifies for it.
  • Coaching, officiating or access to a venue where current British Powerlifting membership is a requirement.

If your reason isn't listed, please contact British Powerlifting (opens in a new tab) before using this service.

No endorsement. Using this service does not mean British Powerlifting endorses, approves or partners with you, your organisation or your offers. Please don't say or suggest it does, or use our name or logo that way. Any promotion you run is your own responsibility.

How it works

It only confirms what you already know. You'll see whether the details you entered match a current British Powerlifting membership, and when it ends. It never returns any member information you didn't enter yourself: no names, email addresses, membership numbers, dates of birth or anything else from our records. Trying to find out more won't work, and breaks the terms of use.

Send at least two of these three:

  • Full name: first_name and last_name (both are needed, and they count as one).
  • Email address: email
  • Membership number: membership_number, with or without the GB prefix.

Every field you send must match the same membership record. Send three with one wrong, and the answer is not_found.

Matching ignores upper/lower case, accents, extra spaces, hyphens and apostrophes. Names must otherwise be exact: use the name the person registered with British Powerlifting, not a nickname or a shortened name.

Request

POSThttps://tools.britishpowerlifting.org/api/v1/membership-check

  • Header Content-Type: application/json, with a Content-Length (chunked bodies are refused).
  • The body must be a JSON object, under 2 KB, containing only the fields below.
  • Always POST, never GET, so personal details never end up in URLs or server logs.
  • Checks are read-only. Set a client timeout of 5–10 seconds; every answer takes at least about a quarter of a second, by design.
FieldTypeNotes
first_namestring ≤ 100Send with last_name
last_namestring ≤ 100Send with first_name
emailstring ≤ 254Case-insensitive
membership_numberstring ≤ 30GB123456 or 123456

Response

200 OK is returned for every completed check, including when no member matched, so a miss isn't an error.

json
{
  "status": "active",
  "membership_expires_on": "2027-03-31",
  "matched_on": ["name", "membership_number"],
  "data_as_of": "2026-10-05T01:14:09Z",
  "data_may_be_stale": false,
  "checked_at": "2026-10-05T09:30:00Z"
}
FieldMeaning
status active: a current member.
expired: the details match a membership that has lapsed (the date is always given).
not_found: we can't confirm a current membership matching every field you sent.
membership_expires_on YYYY-MM-DD or null. For active, the last day the membership is valid (null if we don't hold it). For expired, the day it expired. Always null for not_found.
matched_onWhich of your fields were checked: name, email, membership_number. Never their stored values. Empty for not_found.
data_as_ofWhen our member records were last refreshed (UTC), or null if unknown.
data_may_be_staletrue if the records haven't been refreshed in the last 48 hours.
checked_atWhen this check ran (UTC).

Errors

Errors (other than a 404) return {"error": "<code>", "message": "<human-readable>"}. Branch on error, not on message.

HTTPerrorMeaning
400 insufficient_details Fewer than two of name / email / membership number.
400 incomplete_name Only one of first_name / last_name was sent.
400 invalid_email · invalid_membership_number · invalid_field · field_too_long A field is malformed, isn't a string, or is too long.
400 invalid_json · unknown_field The body isn't a JSON object, or contains a field not listed above.
405 method_not_allowed Not a POST (the response carries Allow: POST).
413 payload_too_large The body is over 2 KB, or has no Content-Length. Checked before the content type.
415 unsupported_media_type The body isn't sent as application/json.
429 rate_limited Too many checks. Wait for the Retry-After header (currently 120 seconds).
404 — The API is not currently available (an ordinary "page not found", not JSON).

Rate limits

To protect members' details from anyone trying to guess them, every check counts towards several limits, shared with the web form:

  • Per IP address: roughly 10 a minute, 60 an hour and 200 a day (IPv6 is counted per /64 network).
  • Unmatched checks per IP address are limited much more tightly than successful ones.
  • Per person: repeated unmatched checks against the same membership number, email address or name are limited, whoever sends them.
  • Overall: a daily ceiling on all checks from everyone.

Responses don't carry rate-limit counters. Over a limit, you get a 429 with a Retry-After header: wait at least that long, and never retry in a tight loop. Never automatically retry a not_found — it counts against the stricter limits and the answer won't change. Exact limits may change without notice.

Check one person when you need to, e.g. when they claim a discount — not whole lists. For higher volumes, contact British Powerlifting (opens in a new tab).

Examples

Call the API from your server, not from a web browser. It deliberately doesn't allow cross-origin (CORS) requests, so JavaScript on your own website can't call it directly. Check from your backend, then pass the result to your page.

Python
import requests

resp = requests.post(
    "https://tools.britishpowerlifting.org/api/v1/membership-check",
    json={"first_name": "Jane", "last_name": "Smith",
          "membership_number": "GB123456"},
    timeout=10,
)
if resp.status_code == 429:
    wait = int(resp.headers.get("Retry-After", "120"))
    raise RuntimeError(f"Rate limited, retry in {wait}s")
resp.raise_for_status()
is_member = resp.json()["status"] == "active"
Node.js (server-side)
const resp = await fetch("https://tools.britishpowerlifting.org/api/v1/membership-check", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email, membership_number }),
  signal: AbortSignal.timeout(10_000),
});
if (resp.status === 429) {
  const wait = Number(resp.headers.get("Retry-After") ?? 120);
  throw new Error(`Rate limited, retry in ${wait}s`);
}
if (!resp.ok) throw new Error(`Check failed: ${resp.status}`);
const isMember = (await resp.json()).status === "active";
PHP
$ch = curl_init("https://tools.britishpowerlifting.org/api/v1/membership-check");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
    CURLOPT_POSTFIELDS => json_encode([
        "email" => $email, "membership_number" => $number]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$body = json_decode(curl_exec($ch), true);
$isMember = curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200
    && ($body["status"] ?? null) === "active";
curl
curl -sS -X POST 'https://tools.britishpowerlifting.org/api/v1/membership-check' \
  -H 'Content-Type: application/json' \
  -d '{"email": "[email protected]",
       "membership_number": "GB123456"}'

Integrating: discounts, testing and what to tell customers

Offering a member discount

  1. At checkout or sign-up, ask for the customer's BP membership number plus their name or email — and tell them you'll check it with British Powerlifting.
  2. Your server calls the API.
  3. If status is active, apply the discount. You can also check membership_expires_on is after the date of the service you're selling.
  4. If it's expired or not_found, ask the customer to check their details or renew in Sport:80. Don't keep retrying variations.

Offering a discount doesn't make you a British Powerlifting partner. Don't present your offer as endorsed or approved by British Powerlifting.

Testing

There's no sandbox: the API checks real member records. Test with your own membership details (or a colleague's, with their permission). Made-up example data always returns not_found and still counts towards the stricter limits, so keep test runs small.

What to show your customer

statusSuggested wording
active“Thanks — your British Powerlifting membership is confirmed (valid until 31 March 2027).”
expired“Your British Powerlifting membership ended on 31 August 2026. If you've just renewed, it can take up to a day to show.”
not_found“We couldn't confirm your membership. Please check your details match your British Powerlifting membership exactly.”

Data freshness

Member records are copied from the British Powerlifting membership system (Sport:80) every night, so a renewal, a new membership or a lapse can take up to a day to show. Every response includes data_as_of, so you can tell how fresh the answer is.

If a customer has just joined or renewed but gets not_found or expired, ask them to show their membership in Sport:80, or try again the next day.

Records last updated 12 Nov 2026 at 02:03 GMT.

Acceptable use

  • Only check people who have given you their details for an authorised purpose and expect you to verify their membership.
  • Don't use the API to find out, guess or enumerate who is a member, to check lists of people, or to build marketing lists.
  • Don't try to use the API to get any more information about a member. It only ever confirms what you sent.
  • You're responsible for your own UK GDPR compliance. Tell people you'll check their membership with British Powerlifting, don't store results without the member's consent (or another clear lawful basis), keep only what you need for as long as you need it, and keep it secure.
  • Don't resell or pass on results. A membership can lapse or renew at any time, so check again rather than relying on an old result.
  • The service is provided "as is", with no guarantee of accuracy or availability, and may be changed or withdrawn at any time. We monitor usage and may block anyone misusing it.

The full terms of use apply. Questions? Contact British Powerlifting (opens in a new tab).