Request employment references programmatically, track them through to consent, and receive the verified record — with webhooks or polling. Available on the Growth and Business plans.
The API mirrors the Reffolio workflow exactly. You create a request; Reffolio emails the previous employer a secure link; they complete a sector-specific form; the candidate consents; you receive a verified, tamper-evident record. You can be notified by webhook at each step, or poll for status.
POST /v1/requests — get a request_id (status pending).referee_submitted webhook (status becomes awaiting_consent).consent_granted and reference_received (status becomes received).GET /v1/references/{id}.An organisation admin generates keys in the dashboard under API. The full key (rfl_live_…) is shown once — store it securely. Send it as a bearer token on every request:
Authorization: Bearer rfl_live_EXAMPLEKEY1234567890Base URL:
https://reference-platform-production.up.railway.appA quick check from your terminal:
curl -H "Authorization: Bearer rfl_live_..." \
https://reference-platform-production.up.railway.app/v1/ping/v1/requestsRequest a reference about a candidate from a previous employer. Reffolio emails the referee a secure link and, once completed, asks the candidate to consent — exactly as the dashboard does.
{
"worker_name": "Sam Jones",
"worker_email": "sam@example.com",
"referee_email": "manager@previousemployer.co.uk",
"referee_name": "A. Manager",
"prev_employer_name": "Previous Employer Ltd",
"template_id": null,
"message": "Optional note shown to the referee."
}{
"request_id": "...",
"status": "pending",
"email_sent": true,
"domain_verified": true
}/v1/requests/{id}Poll one request: its lifecycle status, and the produced reference + consent state once available.
{
"request_id": "...",
"status": "received",
"candidate_name": "Sam Jones",
"referee_email": "manager@previousemployer.co.uk",
"consent_status": "granted",
"reference": {
"reference_id": "...",
"ref_number": "REF-2026-000123",
"content_hash": "770c44...",
"readable": true
}
}/v1/requestsList your organisation’s reference requests with their current lifecycle status.
[
{ "request_id": "...", "status": "awaiting_consent", "candidate_name": "Sam Jones", "consent_status": "pending" }
]/v1/references/{id}Fetch a received reference’s full content. Only references sent to your organisation with consent granted are readable.
{
"reference_id": "...",
"ref_number": "REF-2026-000123",
"candidate_name": "Sam Jones",
"sector": "care",
"content": { "...": "..." },
"content_hash": "770c44...",
"consent_status": "granted"
}The status field on a request moves through these values:
| pending | Request created; the referee has been emailed but hasn’t opened the link. |
| opened | The referee has opened the secure link. |
| awaiting_consent | The referee has completed the reference; waiting for the candidate to consent. |
| received | The candidate consented; the reference is readable. |
| declined | The candidate declined consent; the reference is not released. |
Register a URL and Reffolio will POST a signed JSON payload when events happen. Polling (GET /v1/requests/{id}) is always available as a fallback.
/v1/webhooksRegister an endpoint to receive signed event deliveries. The signing secret is returned ONCE.
{
"url": "https://your-system.example.com/reffolio/hook",
"events": ["referee_submitted", "consent_granted", "reference_received"]
}{
"id": "...",
"url": "https://your-system.example.com/reffolio/hook",
"events": ["referee_submitted", "consent_granted", "reference_received"],
"active": true,
"secret": "whsec_..."
}/v1/webhooksList your registered webhooks and their last delivery status. Secrets are never returned.
[
{ "id": "...", "url": "...", "events": ["..."], "active": true, "last_status": 200 }
]/v1/webhooks/{id}Delete a webhook endpoint.
{
"deleted": true,
"id": "..."
}| referee_submitted | The previous employer has completed the reference. It is held pending the candidate’s consent. |
| consent_granted | The candidate has consented; the reference is now released to you. |
| reference_received | Fired alongside consent_granted — the reference is now readable via GET /v1/references/{id}. |
Each delivery has this shape, with the event name and data:
{
"event": "reference_received",
"data": {
"reference_id": "...",
"ref_number": "REF-2026-000123"
}
}Verify authenticity using the X-Reffolio-Signature header, which is sha256= followed by the HMAC-SHA256 of the raw request body, keyed with your webhook secret:
import hmac, hashlib
def verify(secret, raw_body, header):
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, header)Delivery is best-effort: respond with a 2xx status quickly. If your endpoint is unavailable, use polling to reconcile any missed events.
Errors return a JSON body { "detail": "..." } with a standard HTTP status:
| 401 | Missing or invalid API key, or the key was revoked. |
| 402 | Your plan does not include API access. Upgrade to Growth or Business. |
| 403 | The resource belongs to another organisation, or consent has not been granted. |
| 404 | The request, reference or webhook was not found. |
| 422 | Validation error (e.g. a required field is missing or the URL is invalid). |
Generate your first key in the dashboard, or talk to us about integrations.
Go to dashboard