VolunteerBadge has a simple REST API for managing volunteers, sending applications, ordering background checks, and receiving real-time events. If you'd rather not write code, see Import volunteers for the spreadsheet importer, or Connect to Claude to drive everything in plain English.
Base URL
https://www.volunteerbadge.com/api/v1. Requests and responses are JSON.Authentication
Create an API key in Settings → API (you'll accept the CRA End-User Agreement the first time). Keys look like vb_live_… — treat them like a password and never expose one in client-side code. Send it as a bearer token on every request:
Authorization: Bearer vb_live_xxxxxxxxxxxxxxxxxxxxEndpoints
| Method & path | What it does |
|---|---|
GET /api/v1/volunteers | List volunteers (paginated, filter by status). |
POST /api/v1/volunteers | Create a volunteer (idempotent on email). |
POST /api/v1/applications | Send a volunteer application by email, SMS, or shareable link. |
POST /api/v1/checks | Order a background check for a subject. |
GET /api/v1/checks/{id} | Get a check’s status and result. |
GET /api/v1/credits | Get your remaining check-credit balance. |
Create a volunteer
Push a person into VolunteerBadge — e.g. migrating a roster or syncing from another system. Posting the same email twice returns the existing record instead of duplicating it.
curl -X POST https://www.volunteerbadge.com/api/v1/volunteers \
-H "Authorization: Bearer vb_live_..." \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jamie",
"last_name": "Rivera",
"email": "jamie@example.com",
"phone": "443-790-8081",
"dob": "1981-05-29",
"state": "FL",
"last_check_date": "2025-06-01",
"fcra_authorization_on_file": true,
"status": "approved"
}'
# → { "volunteerId": "f883...", "created": true }fcra_authorization_on_file is required
true only for people whose signed FCRA authorization you actually hold — it's what allows checks (and auto-rescreen) to run for them.List volunteers
curl "https://www.volunteerbadge.com/api/v1/volunteers?status=approved&page=1&limit=25" \
-H "Authorization: Bearer vb_live_..."
# → { "volunteers": [ { "id": "...", "first_name": "...", "status": "approved", ... } ],
# "pagination": { "page": 1, "limit": 25, "total": 42, "totalPages": 2 } }Order a background check
Requires firstName, lastName, dob, ssn, address, city, state, zip (middle name optional). This consumes 1 credit.
curl -X POST https://www.volunteerbadge.com/api/v1/checks \
-H "Authorization: Bearer vb_live_..." \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jamie", "lastName": "Rivera",
"dob": "1981-05-29", "ssn": "123456789",
"address": "12112 Blue Hill Trail", "city": "Lakewood Ranch",
"state": "FL", "zip": "34211"
}'
# → { "checkId": "...", "status": "processing", "result": null, "message": "..." }Poll GET /api/v1/checks/{id} for the result, or subscribe to the check.complete webhook (below) so you're notified instead of polling.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing or invalid field — see the error message. |
| 401 | Missing or invalid API key. |
| 402 | Insufficient credits — buy more in Billing. |
| 403 | CRA End-User Agreement must be re-accepted in Settings → API. |
| 404 | Resource not found. |
| 429 | Rate limited — slow down and retry. |
Webhooks
Instead of polling, register a URL in Settings → Webhooks and VolunteerBadge will POST to it when things happen. Available events:
| Event | Fires when |
|---|---|
check.complete | A background check finishes (clear or consider). |
check.error | A check fails to process. |
application.submitted | A volunteer submits their application. |
volunteer.created | A new volunteer record is created. |
Each delivery is a JSON POST with two headers — X-VolunteerBadge-Event (the event name) and X-VolunteerBadge-Signature (an HMAC-SHA256 of the raw body, signed with your endpoint's secret):
POST (your endpoint)
X-VolunteerBadge-Event: check.complete
X-VolunteerBadge-Signature: 9f86d081...
{
"event": "check.complete",
"data": { "checkId": "...", "volunteerId": "...", "result": "clear" },
"timestamp": "2026-06-24T18:00:00.000Z"
}Always verify the signature before trusting a payload. In Node:
import crypto from 'crypto';
function verify(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}Prefer no-code?


