Start here

Getting Started

ReceiptorX lets you verify Nigerian bank receipts using AI — detecting fraud, edited fields, and fake screenshots in milliseconds. Here's how to go from zero to your first verification.

1
Create an account & generate an API key
Sign up at receiptor-x.onrender.com, go to API Keys, and click Generate Key. Copy it immediately — you won't see the full key again.
Your API key looks like this
rcx_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6
2
Make your first verification request
Send a POST to /api/verify with the receipt image and the payment details you expect to see on it.
cURL
curl -X POST https://receiptor-x.onrender.com/api/verify \
  -H "X-Api-Key: rcx_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "data:image/jpeg;base64,...",
    "config": {
      "expectedRecipientName":  "Ayo David",
      "expectedBankName":       "GTBank",
      "expectedAmount":         5000,
      "expectedAccountNumber":  "0123456789"
    }
  }'
3
Read the result
You get back a valid boolean, a human-readable reason, and the detected fields the AI actually extracted from the image.
JSON Response
{
  "valid":    true,     // ← the only thing you need to check
  "reason":   "All checks passed.",
  "detected": {
    "bank":          "GTBank",
    "amount":        5000,
    "accountNumber": "0123456789",
    "name":          "Ayo David",
    "date":          "2026-06-27"
  }
}
That's all you need. Read on for the full reference — or jump straight to the Verify Receipt section for every available config option.
Security

Authentication

The verify endpoint uses API key authentication via the X-Api-Key header. The dashboard and SSE stream use JWT Bearer tokens.

API Key
For POST /api/verify. Pass your key in the X-Api-Key header.
HTTP Header
X-Api-Key: rcx_live_your_key_here
JWT Bearer
For dashboard routes and the SSE stream. Obtained after login — short lived, auto-renewed.
HTTP Header
Authorization: Bearer <jwt>
Keep keys secret. Never put an rcx_live_ key in client-side JavaScript, a Git repository, or a public URL. Store it as an environment variable on your server.
Core API

Verify Receipt

The main endpoint. Submit a receipt image with the payment details you expect — the AI checks every field and returns a definitive result with an explanation.

POST /api/verify Auth: X-Api-Key

What the AI checks

Recipient name match
Bank name & logo
Amount & currency
Account number (NUBAN)
Transaction date & age
Font & pixel forensics
Brand colour integrity
Screenshot vs real receipt

Request fields

FieldTypeRequiredDescription
imagestringrequiredBase64 data URL (data:image/jpeg;base64,…) or public HTTPS image URL
config.expectedRecipientNamestringrequiredName as it should appear on the receipt
config.expectedBankNamestringrequiredBank to verify — e.g. GTBank, OPay, Kuda
config.expectedAmountnumberrequiredExact amount as a number (no currency symbol)
config.expectedAccountNumberstringrecommended10-digit NUBAN account number. Strongly recommended — edited account digits are the #1 fraud vector in Nigerian scams
config.currencystringoptionalCurrency code — default NGN
config.allowedNameVariationsstring[]optionalAcceptable name alternatives, e.g. ["A. David", "Ayo D."]
config.maxDateAgeDaysnumberoptionalMax receipt age in days — default 1
config.timezonestringoptionalIANA timezone — default Africa/Lagos

Code examples

cURL

      

Response — valid receipt

JSON · 200 OK
{
  "valid":      true,
  "core_valid": true,
  "date_valid": true,
  "reason":     "All checks passed.",
  "requestId":  "8f3c2a1b-4d9e-…",
  "detected": {
    "bank":          "GTBank",
    "amount":        5000,
    "name":          "Ayo David",
    "accountNumber": "0123456789",
    "date":          "2026-06-27",
    "transactionId": "220626…"
  }
}

Response — account number fraud detected

JSON · 200 OK
{
  "valid":      false,
  "core_valid": false,
  "date_valid": true,
  "reason":     "Account number on receipt (0123456788) does not match expected (0123456789). Last digit appears digitally altered.",
  "requestId":  "4d9a7e2f-…",
  "detected": {
    "bank":          "GTBank",
    "amount":        5000,
    "accountNumber": "0123456788",  // what the AI actually saw
    "date":          "2026-06-27"
  }
}
Real-time

Live Events (SSE)

Subscribe to a real-time stream of verification events for your dashboard. Every new result is pushed to you instantly — no polling, no delays.

GET /api/events/stream Auth: ?token=<jwt>
The browser's EventSource API doesn't support custom headers. Pass your JWT as a ?token= query parameter — the server handles it securely server-side.
JavaScript
const source = new EventSource(
  `https://receiptor-x.onrender.com/api/events/stream?token=${jwtToken}`
);

source.addEventListener('connected', () => {
  console.log('🟢 Stream connected');
});

source.addEventListener('verification', e => {
  const event = JSON.parse(e.data);
  // event = { valid, bank, amount, accountNumber, reason, requestId, createdAt }

  if (event.valid) {
    console.log('✓ Valid', event.bank, 'NGN', event.amount);
  } else {
    console.warn('✗ Flagged:', event.reason);
  }
});

source.onerror = () => source.close(); // reconnect as needed

Event payload fields

FieldTypeDescription
validbooleanOverall result
bankstring|nullDetected bank name
amountnumber|nullDetected amount
accountNumberstring|nullDetected NUBAN account number
reasonstringHuman-readable explanation
requestIdstringUUID — matches the requestId in your audit log
createdAtstringISO 8601 timestamp
Real-time

Webhooks

Webhooks are HTTP POST requests that ReceiptorX sends to your server every time a verification completes. Unlike SSE, they work server-to-server without a persistent connection.

Receipt submitted
AI verifies
Webhook fired
Your server

Events

EventFired when
verification.completeReceipt passed all checks (valid: true)
verification.failedReceipt failed any check (valid: false)

Payload

POST to your endpoint · application/json
{
  "event":         "verification.complete",
  "valid":         true,
  "bank":          "GTBank",
  "amount":        5000,
  "accountNumber": "0123456789",
  "reason":        "All checks passed.",
  "requestId":     "8f3c2a1b-…",
  "createdAt":     "2026-06-27T12:00:00.000Z"
}

Verifying the signature

Every request includes an X-ReceiptorX-Signature header. Verify it on your server to confirm the request came from ReceiptorX and wasn't tampered with.

Node.js — signature verification
import { createHmac, timingSafeEqual } from 'crypto';

function verifySignature(rawBody, signature, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(signature);

  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b); // timing-safe compare
}

// In your Express route:
app.post('/webhooks/rcx', express.raw({ type: '*/*' }), (req, res) => {
  const sig = req.headers['x-receiptorx-signature'];
  if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // handle event.valid, event.bank, etc.
  res.sendStatus(200);
});
Respond with 2xx quickly. ReceiptorX retries failed deliveries up to 3 times with exponential backoff. Return 200 as fast as possible and process the event asynchronously.
Reference

Error Codes

All errors include a message field and an X-Request-ID header for tracing.

StatusMeaningWhat to do
200OKCheck valid field — the request succeeded even if the receipt is invalid
400Bad RequestFix missing or invalid fields in your request body
401UnauthorizedCheck your API key — wrong format, missing, or expired
403ForbiddenKey has been revoked — generate a new one
429Rate LimitedCheck Retry-After header and slow down
502AI Engine ErrorThe AI model failed — retry with exponential backoff
500Server ErrorRetry; report persistent issues with the X-Request-ID
Reference

Rate Limits

Limits are applied per API key. Check the response headers to see how many requests you have left.

30
verifications / minute
200
requests / 15 min (global)
10 MB
max request body
10
webhooks per account
Response headers when limited
HTTP/1.1 429 Too Many Requests
Retry-After:           42
RateLimit-Limit:       30
RateLimit-Remaining:   0
RateLimit-Reset:       1751026800
Libraries

SDK & Libraries

Drop the zero-dependency client into your project, or use any HTTP library directly.

JavaScript / TypeScript (zero dependencies)

receiptorx-client.js
export class ReceiptorX {
  constructor(apiKey) {
    this.apiKey  = apiKey;
    this.baseUrl = 'https://receiptor-x.onrender.com';
  }

  async verify(image, config) {
    const res = await fetch(`${this.baseUrl}/api/verify`, {
      method:  'POST',
      headers: { 'X-Api-Key': this.apiKey, 'Content-Type': 'application/json' },
      body:    JSON.stringify({ image, config }),
    });
    if (!res.ok) throw new Error(`ReceiptorX ${res.status}: ${(await res.json()).message}`);
    return res.json();
  }
}

// Usage:
const rcx    = new ReceiptorX('rcx_live_…');
const result = await rcx.verify(imageDataUrl, {
  expectedRecipientName: 'Ayo David',
  expectedBankName:      'GTBank',
  expectedAmount:        5000,
  expectedAccountNumber: '0123456789',
});

if (result.valid) {
  console.log('Receipt is genuine ✓');
} else {
  console.warn('Fraud detected:', result.reason);
}

npm / pip packages

receiptorx
Coming soon on npm
receiptorx
Coming soon on PyPI
Status

Health Check

Use this unauthenticated endpoint to check if the API is up before making requests.

GET /health No auth required
JSON · 200 OK
{
  "status":    "ok",
  "service":   "ReceiptorX",
  "timestamp": "2026-06-27T12:00:00.000Z"
}