An API that’s as careful as you are
Create referrals from your website, CRM or app, read outcomes, and react to events in real time. Base URL: /api/v1/
Authentication
Server integrations authenticate with an API key created under Developers → API keys. Keys are bound to one workspace, carry explicit scopes and can be restricted by IP and expiry. Test-mode keys never affect live analytics or rewards.
Authorization: ApiKey gmr_live_<prefix>.<secret>Create a referral
Referral creation atomically records the contact, referral, opportunity, history, audit and outbox events.
curl https://api.getmereferrals.com/api/v1/referrals/ \
-H "Authorization: ApiKey $GMR_KEY" \
-H "Idempotency-Key: 7c2b6c1e-0f2d-4a51-9a51-1f7f2b0f6d11" \
-H "Content-Type: application/json" \
-d '{
"source_entity_id": "<partner uuid>",
"destination_entity_id": "<team uuid>",
"service_id": "<service uuid>",
"source_channel": "api",
"priority": "normal",
"summary": "Looking for help with tax planning.",
"consent_obtained": true,
"consent_method": "web_form",
"contact": { "first_name": "Ada", "last_name": "Lovelace", "email": "ada@example.com" }
}'Idempotency
API-key referral creation, accept and decline require an Idempotency-Key. Keys are kept for 24 hours. Repeating the exact request returns the stored response with Idempotency-Replayed: true; reusing a key with a different body is rejected.
Errors
Failures use RFC 9457 problem details with a stable code, field errors and a request ID to quote to support.
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "The request could not be processed.",
"code": "invalid",
"request_id": "0fe045ab-c04b-4892-8f89-7ab101488b07",
"errors": { "service_id": ["Object does not belong to the active tenant."] }
}Webhooks
Subscribe to events such as referral.created, referral.accepted and opportunity.won. Each request is signed with HMAC-SHA256 over the webhook ID, timestamp and exact raw body.
import crypto from "node:crypto";
export function verify(req, rawBody, secret, toleranceSec = 300) {
const id = req.headers["x-assoc-webhook-id"];
const ts = Number(req.headers["x-assoc-webhook-timestamp"]);
const sig = req.headers["x-assoc-webhook-signature"];
if (Math.abs(Date.now() / 1000 - ts) > toleranceSec) return false; // replay window
const expected = "v1=" + crypto.createHmac("sha256", secret).update(`${id}.${ts}.${rawBody}`).digest("hex");
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}The signature header has the form v1=<hex>. Always verify against the exact raw request body.
Turn your partner network into a measurable growth channel.
See how teams capture, route and attribute every referral in one place.

