Developers

Certificate API

Issue, verify, and manage verifiable certificates programmatically. Integrate 9th Drop's certificate engine into any school, LMS, or enterprise platform.

v1.0 Stable Business Plan Required REST + Webhooks

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.

All API responses are JSON. All requests must include an 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

  1. Upgrade to the Business plan
  2. Go to Vendor Dashboard → Settings → API Keys
  3. Click Generate New Key, name it, and copy it immediately (shown only once)

Sending the key

Request Header
Authorization: Bearer vk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Never expose your API key in client-side JavaScript or public repositories. Treat it like a password. If compromised, regenerate it immediately from your dashboard.

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.

Starter
₦0/mo
No API access
Pro
₦9,900/mo
No API access
Business
₦24,900/mo
100 req/hour · Webhooks · All endpoints
Need higher rate limits or custom SLA? Contact us for Enterprise pricing.

Error Handling

All errors return a consistent JSON structure with an HTTP status code.

Error Response
{
  "success": false,
  "error": {
    "code":    "unauthorized",
    "message": "Missing API key. Pass Authorization: Bearer <key>"
  }
}
HTTP CodeError CodeMeaning
400bad_requestMissing or invalid parameters
401unauthorizedMissing, invalid, or inactive API key
403subscription_requiredYour plan does not include API access
404not_foundCertificate or endpoint not found
410revokedCertificate has been revoked
429rate_limitedToo many requests — slow down
500server_errorInternal 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.

Rate Limit Exceeded (429)
{
  "success": false,
  "error": {
    "code":    "rate_limited",
    "message": "Rate limit exceeded: 100 requests/hour"
  }
}
Implement exponential backoff when you receive a 429. Wait at least 60 seconds before retrying.

List Templates

Returns all active certificate background templates available on the platform.

GET /api/certificate/templates No parameters required
Request
GET https://9thdrop.com/api/certificate/templates
Authorization: Bearer vk_live_your_key
Response 200
{
  "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.

POST /api/certificate/issue Issue a new certificate

Request Parameters

ParameterTypeRequiredDescription
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.
Request Body
{
  "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."
}
Response 201 — Created
{
  "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 /api/certificate/verify/{certificate_id} Verify certificate authenticity
GET https://9thdrop.com/api/certificate/verify/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Authorization: Bearer vk_live_your_key
Response 200
{
  "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).

GET /api/certificate/download/{certificate_id} Get download / print URL
{
  "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."
}
For automated PDF generation, open 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.

GET /api/certificate/list Paginated list
Query ParamDefaultDescription
page1Page number
limit20Results 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

POST to your webhook_url
{
  "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

Official SDKs for Node.js, Python, and PHP are in development. For now, use the REST endpoints directly with the code examples above.

The API is a standard REST API — any HTTP client works. No special SDK is required.

Recommended libraries

LanguageLibraryInstall
JavaScriptNative fetch / axiosnpm install axios
Pythonrequestspip install requests
PHPNative cURL / Guzzlecomposer require guzzlehttp/guzzle
Rubyfaradaygem install faraday

Need help integrating? Contact our developer support or visit the Help Center.