Overview
The 9th Drop Certificate API lets external platforms — schools, bootcamps, corporate training systems, and LMS providers — issue, verify, and manage blockchain-independent verifiable certificates through a simple REST API.
Certificates are rendered using your chosen template backgrounds, include dual signatures (system + instructor), QR-code verification, and are accessible via a permanent public URL.
Authorization: Bearer <key> header. HTTPS is required in production.Authentication
Every API request requires a Bearer token in the Authorization header. You generate API keys from your vendor dashboard.
Getting your API key
- Upgrade to the Business plan
- Go to Vendor Dashboard → Settings → API Keys
- Click Generate New Key, name it, and copy it immediately (shown only once)
Sending the key
Authorization: Bearer vk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Base URL
# Production https://9thdrop.com/api/certificate/{endpoint} # Example https://9thdrop.com/api/certificate/issue
All endpoints live under /api/certificate/. No versioning prefix is needed for v1.
Subscription Plans & Rate Limits
API access is available on the Business plan only. Each plan enforces a per-hour rate limit.
Error Handling
All errors return a consistent JSON structure with an HTTP status code.
{
"success": false,
"error": {
"code": "unauthorized",
"message": "Missing API key. Pass Authorization: Bearer <key>"
}
}
| HTTP Code | Error Code | Meaning |
|---|---|---|
400 | bad_request | Missing or invalid parameters |
401 | unauthorized | Missing, invalid, or inactive API key |
403 | subscription_required | Your plan does not include API access |
404 | not_found | Certificate or endpoint not found |
410 | revoked | Certificate has been revoked |
429 | rate_limited | Too many requests — slow down |
500 | server_error | Internal error — contact support |
Rate Limits
Rate limits are applied per API key, per rolling 60-minute window. Every request is logged — even failed ones count toward your limit.
{
"success": false,
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded: 100 requests/hour"
}
}
List Templates
Returns all active certificate background templates available on the platform.
GET https://9thdrop.com/api/certificate/templates Authorization: Bearer vk_live_your_key
{
"success": true,
"count": 6,
"data": [
{
"id": 1,
"name": "Gold Wave",
"slug": "gold-wave",
"tier": "free",
"price": 0,
"currency": "NGN"
},
...
]
}
Issue Certificate
Programmatically issue a certificate to any recipient. The certificate is immediately available at its verify_url.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
recipient_name |
string | required | Full name of the certificate recipient |
recipient_email |
string | required | Email address of the recipient |
course_title |
string | required | Name of the course or program completed |
product_id |
integer | optional | Your product ID to link the certificate to a course. Required if you have no products. |
template_id |
integer | optional | Certificate template ID from /templates. Defaults to 1 (Gold Wave). |
cert_title |
string | optional | Override the certificate headline. Default: "CERTIFICATE" |
cert_body |
string | optional | Override the body description text. |
{
"recipient_name": "Adeline Palmerston",
"recipient_email": "adeline@example.com",
"course_title": "Advanced Web Development",
"template_id": 1,
"cert_title": "CERTIFICATE",
"cert_body": "For outstanding achievement in web development."
}
{
"success": true,
"certificate_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recipient_name": "Adeline Palmerston",
"recipient_email": "adeline@example.com",
"course_title": "Advanced Web Development",
"verify_url": "https://9thdrop.com/certificate/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"download_url": "https://9thdrop.com/api/certificate/download/a1b2c3d4-...",
"issued_at": "2026-05-30T10:00:00+00:00"
}
Verify Certificate
Check if a certificate is valid. Use this endpoint when scanning QR codes or validating certificates submitted by applicants.
GET https://9thdrop.com/api/certificate/verify/a1b2c3d4-e5f6-7890-abcd-ef1234567890 Authorization: Bearer vk_live_your_key
{
"success": true,
"is_valid": true,
"certificate_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recipient_name": "Adeline Palmerston",
"course_title": "Advanced Web Development",
"issued_at": "2026-05-30T10:00:00+00:00",
"verify_url": "https://9thdrop.com/certificate/a1b2c3d4-..."
}
Download Certificate
Returns the public view URL for a certificate. The certificate is rendered as an HTML page optimised for browser print-to-PDF (A4 landscape).
{
"success": true,
"certificate_id": "a1b2c3d4-...",
"view_url": "https://9thdrop.com/certificate/a1b2c3d4-...",
"print_pdf_url": "https://9thdrop.com/certificate/a1b2c3d4-...",
"instructions": "Open view_url in a browser and use Print → Save as PDF for A4 landscape output."
}
view_url with Puppeteer or headless Chrome and call page.pdf({ format: 'A4', landscape: true }).List Certificates
Returns a paginated list of all certificates issued under your account.
| Query Param | Default | Description |
|---|---|---|
page | 1 | Page number |
limit | 20 | Results per page (max 50) |
GET https://9thdrop.com/api/certificate/list?page=1&limit=20
Webhooks
Set a webhook_url on your API key to receive a real-time POST notification whenever a certificate is issued via the API.
Configuring your webhook
Set the URL in your dashboard under Settings → API Keys → Edit Key → Webhook URL. Must be a publicly accessible HTTPS endpoint.
Payload
{
"event": "certificate.issued",
"certificate_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recipient": "Adeline Palmerston",
"email": "adeline@example.com",
"course": "Advanced Web Development",
"issued_at": "2026-05-30T10:00:00+00:00"
}
The webhook fires with a 5-second timeout. Your endpoint must respond with 2xx — no retries on failure in v1.
Verify authenticity by checking the X-Vendo-Event header equals certificate.issued.
Code Examples
JavaScript / Node.js
// Issue a certificate with fetch const response = await fetch( "https://9thdrop.com/api/certificate/issue", { method: "POST", headers: { "Authorization": "Bearer vk_live_your_key_here", "Content-Type": "application/json", }, body: JSON.stringify({ recipient_name: "Adeline Palmerston", recipient_email: "adeline@example.com", course_title: "Advanced Web Development", template_id: 1, }), } ); const data = await response.json(); console.log(data.verify_url); // https://...
PHP / cURL
// Issue a certificate with cURL $ch = curl_init("https://9thdrop.com/api/certificate/issue"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer vk_live_your_key_here", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "recipient_name" => "Adeline Palmerston", "recipient_email" => "adeline@example.com", "course_title" => "Advanced Web Development", "template_id" => 1, ]), ]); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); echo $data["verify_url"]; // https://...
Python
import requests response = requests.post( "https://9thdrop.com/api/certificate/issue", headers={ "Authorization": "Bearer vk_live_your_key_here", "Content-Type": "application/json", }, json={ "recipient_name": "Adeline Palmerston", "recipient_email": "adeline@example.com", "course_title": "Advanced Web Development", "template_id": 1, } ) data = response.json() print(data["verify_url"])
Verify a certificate
# cURL one-liner curl -H "Authorization: Bearer vk_live_your_key" \ https://9thdrop.com/api/certificate/verify/YOUR_CERT_UUID
SDKs & Libraries
The API is a standard REST API — any HTTP client works. No special SDK is required.
Recommended libraries
| Language | Library | Install |
|---|---|---|
| JavaScript | Native fetch / axios | npm install axios |
| Python | requests | pip install requests |
| PHP | Native cURL / Guzzle | composer require guzzlehttp/guzzle |
| Ruby | faraday | gem install faraday |
Need help integrating? Contact our developer support or visit the Help Center.