ExamInfo Reseller API

Sell WAEC, NECO, NABTEB and JAMB PINs on your own website or app.

New to APIs? Start here

An API lets your website talk to ExamInfo by itself. Your live key is your secret password, so keep it on your server only. Your wallet pays for each PIN you sell. Your reference is a unique number you make for every sale, so one sale can never be charged twice. A webhook is covered in section 5 in plain words. If you have no developer, send this page to one.

1. Getting started

1) Register at /become-a-reseller and pay the one-time registration fee (N3,000). 2) You receive a test key, a live key and a webhook secret. 3) Fund your wallet by transfer; the owner credits it. 4) Build with the test key first, then switch to the live key.

Base URL:

https://YOUR-SERVER/api/v1

All requests and replies are JSON. Amounts are in Naira (whole numbers).

2. Authentication

Send your key in the Authorization header on every call (or X-API-Key).

Authorization: Bearer ei_live_xxxxxxxxxxxxxxxx

Test key (ei_test_...): returns fake PINs, uses no wallet money and never calls the supplier. Live key (ei_live_...): real PINs, charged from your wallet. Keep keys on your server, never in a browser or app.

If a key leaks, ask the owner for new keys. The old ones stop working immediately.

3. Endpoints

GET/balance

Your wallet balance.

{ "ok": true, "data": { "balance": 25000, "currency": "NGN", "mode": "live" } }

GET/products

Products and your prices. code is what you send when buying.

{ "ok": true, "data": [
  { "code": "WAEC", "name": "WAEC Result Checking PIN", "group": "WAEC", "price": 3400, "currency": "NGN", "requires": [], "max_quantity": 5 },
  { "code": "JAMB_UTME", "name": "JAMB UTME Registration PIN", "group": "JAMB", "price": 7900, "requires": ["profile_code","email","phone"], "max_quantity": 1 }
] }

JAMB Questions and Answers practice access: code JAMB_PRACTICE, requires name, email and reg (JAMB registration number). The reply has an access_url to give the student, valid for the hours shown in access_hours.

POST/orders

Buy PINs or tokens. reference is yours: 8 to 64 letters, numbers, - or _, new for every purchase.

{ "product": "WAEC", "quantity": 2, "reference": "ORD-2026-000123" }

JAMB products also need profile_code (10 digits), email and phone, quantity 1.

{ "ok": true, "data": { "reference": "ORD-2026-000123", "order_id": "ROXXXX", "product": "WAEC", "quantity": 2,
  "unit_price": 3400, "amount": 6800, "status": "delivered", "mode": "live",
  "pins": [ { "type": "Serial", "value": "1234567890" }, { "type": "PIN", "value": "123456789012" } ] } }

status is delivered, processing (wait for the webhook or check the order) or failed (wallet refunded). HTTP 201 = delivered, 202 = processing.

GET/orders/{reference}

Check one order. GET/orders?limit=20 lists recent orders.

GET/ping

Health check (no key needed).

4. Code samples

Buy 1 WAEC PIN:

5. Webhooks

In plain words: a webhook is a doorbell for your website. When an order finishes, ExamInfo presses it by sending a message to the web address you gave us, and your site can show the PIN to your customer straight away. It is optional. Leave the address empty if you have no developer.

When an order finishes (or fails) we POST to your webhook URL: { "event": "order.delivered", "data": { ...order } }. Events: order.delivered, order.failed. Reply with any 2xx. We retry a few times if you do not.

Check the X-ExamInfo-Signature header: sha256= + HMAC-SHA256 of the raw body using your webhook secret.

// Node.js
const crypto = require('crypto');
const sig = 'sha256=' + crypto.createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex');
if (sig !== req.headers['x-examinfo-signature']) return res.sendStatus(401);

6. Errors

Errors look like { "ok": false, "error": { "code": "insufficient_balance", "message": "..." } }

HTTPcodeMeaning
401invalid_keyKey missing or wrong
403account_disabledYour account is switched off
400bad_reference / bad_quantity / bad_jsonFix the request
400unknown_productUse a code from /products
400bad_profile_code / bad_email / bad_phoneJAMB details wrong
402insufficient_balanceWallet too low (balance and needed amount are returned)
409product_unavailableOut of stock right now
409reference_reusedSame reference used for a different order
422profile_not_foundJAMB profile code not found
429rate_limitedToo many requests
502supplier_failedCould not complete; wallet refunded
503api_offAPI switched off for now

7. Rules

No double buying. Send the same reference again and you get the first order back ("duplicate": true), never a second purchase. If a call times out, repeat it with the same reference.

Limits. 120 requests a minute and 30 orders a minute per key.

Processing orders. Your money is held until the supplier answers. Do not buy again; wait for the webhook or call GET /orders/{reference}.

Test mode. Use the test key to try everything for free.

Machine-readable spec: /api/openapi.json