Show your executives, events, communiqués, committees and programmes on your own website, let visitors check a membership card and apply to join — straight from Membership, always up to date. Paste a widget, or call the API from your own code.
In your group's officers' console: Website & API → Create key.
The key is shown once. Revoke it from the same page at any time.
Add the script once, anywhere on the page, then a <div> wherever a widget should appear:
<div data-membership="executives" data-key="mo_pk_YOUR_PUBLIC_KEY"></div> <script src="https://membergate.org/embed.js" defer></script>
| data-membership | Shows |
|---|---|
| group | Name, tagline, about, and the join button |
| executives | The current executive with photos and offices |
| past-executives | The roll of past executives with their tenure |
| events | Upcoming events with theme and a Register button when registration is open (guests get a QR entry pass) |
| communiques | The latest communiqués; add data-full="true" to print the newest one in full |
| committees | Committees and subcommittees, their purpose, chairman and members |
| programmes | Programmes and publicity that are running |
| notices | Notices and news that are running |
| verify | A box to check a membership card: name, status and whether dues are up to date |
| join | Just the "Apply for membership" button (data-label changes its text) |
Options on any widget: data-limit="3", data-theme="dark", data-accent="#7A1F2B" (your colour), data-font="inherit" (use your site's font), data-credit="false" (hide "Powered by"). Widgets draw inside their own shadow root, so your site's styles and theirs never clash.
Base address https://membergate.org/api/v1. Send the key as Authorization: Bearer mo_pk_…. Public keys also work from the browser on their allowed websites. Answers are JSON; times are ISO 8601 (UTC), dates YYYY-MM-DD.
| Request | Returns |
|---|---|
| GET /group | Profile: name, tagline, about, history, founding date, contacts, logo, colours, join_url, portal_url |
| GET /executives | { current: [...], past: [...] } — office, name, photo_url, bio, starts_on, ends_on |
| GET /posts?kind=programme,notice | Running programmes, publicity, notices and news |
| GET /events | Upcoming public events: title, kind, theme, speakers, venue, starts_at, ends_at, register_url |
| GET /communiques | Published communiqués: heading, event, speakers, theme, intro, resolutions[], signed, url |
| GET /communiques/{id} | One communiqué |
| GET /committees | Committees and subcommittees: name, kind, purpose, mandate, chair, members[] with roles |
| GET /directory?q=&type=business | The members directory, when the group makes it public |
| GET /verify/{member number} | { found, full_name, member_number, status, category, member_since, dues_up_to_date } |
// In a page (public key)
const res = await fetch('https://membergate.org/api/v1/executives', { headers: { Authorization: 'Bearer mo_pk_…' } });
const { current } = await res.json();
current.forEach((t) => console.log(t.office, t.name));
# From a terminal
curl -H "Authorization: Bearer mo_pk_…" https://membergate.org/api/v1/events
// GET /api/v1/events
[{ "id": "115c79db-…", "title": "Quarter 4 Business Breakfast Meeting", "kind": "business_breakfast",
"theme": "Cape Town Convention: …", "speakers": ["Mrs. Olubunmi Kuku, Managing Director/Chief Executive, FAAN", "…"],
"venue": "Radisson Blu, Ikeja GRA", "starts_at": "2026-11-19T07:00:00.000Z", "ends_at": "2026-11-19T11:00:00.000Z",
"status": "scheduled", "register_url": "https://membergate.org/register/9f3c…" }]
| Request | Does |
|---|---|
| GET /members?status=active&updated_since=… | The member register (number, name, contacts, category, status, card link); updated_since for syncing |
| GET /members/{member number} | One member, with what they owe and whether their dues are up to date |
| POST /applications | Sends an application from your own form: full_name, email, phone, date_of_birth, category. It waits for approval in the officers' console like any other; the answer's next is the link to send the applicant to create their account |
| GET /directory | The directory as members see it |
| POST /members | Up to 1,000 members at a time: { members: [{ full_name, email, phone, date_of_birth, category, chapters: [..], member_number, joined_at, address, fields: { "Label": value } }], mode: "invite" | "active" | "pending", dry_run, send_messages }. Every row is checked and the answer gives each row's result; with dry_run: true nothing is saved |
| GET /schema | The columns a member row may carry for your group, with the categories, chapters and field choices |
| GET /template.xlsx | The group's Excel template |
| GET /imports/{id} | An upload's rows and what happened to each |
<?php // PHP: send an application from your site's own form
$ch = curl_init('https://membergate.org/api/v1/applications');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('MEMBERS_SECRET_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['full_name' => $_POST['name'], 'email' => $_POST['email'], 'phone' => $_POST['phone'], 'date_of_birth' => $_POST['dob']])]);
$answer = json_decode(curl_exec($ch), true);
Never put a secret key in a page, an app or a URL: requests with ?key=mo_sk_… are refused.
Website & API → Webhooks: Membership POSTs to your address when something changes — member.joined, member.activated, member.updated, member.status, officer.changed, charge.created, payment.recorded, event.created, communique.published. A failed delivery is retried with growing gaps, up to 8 times.
POST https://your-site/hooks/members
X-Members-Event: communique.published
X-Members-Signature: hex(HMAC-SHA256(raw body, your webhook secret))
{ "event": "communique.published", "group_id": "…", "at": "2026-11-19T12:40:00.000Z", "data": { "id": "…", "heading": "…", "resolutions": ["…"] } }
// Node: check the signature before trusting the body
const ok = crypto.timingSafeEqual(Buffer.from(req.get('x-members-signature')),
Buffer.from(crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex')));
<?php // PHP
$ok = hash_equals(hash_hmac('sha256', file_get_contents('php://input'), $secret), $_SERVER['HTTP_X_MEMBERS_SIGNATURE'] ?? '');