← Slimpay.ng

Used by every "Try It" panel across these docs to call app.slimpay.ng for real. Get one from Authentication — register or log in, then paste the token here. Stored only in this browser (localStorage), never sent anywhere but the Slimpay API, and auto-cleared after 8 hours.

SDKs

Lookups

Slimpay calls your server in two situations. Both use the same signed-request mechanism and the same LookupHandler class, but each has its own secret, so each gets its own handler instance.

LookupWhenPurpose
Student lookupA parent types a student ID on Slimpay's checkoutConfirm the student exists and attach their details to the payment
Invoice lookupYour portal calls collectInvoice()Tell Slimpay the invoice amount and which student it belongs to

The request Slimpay sends

http
POST /your/endpoint HTTP/1.1
Content-Type: application/json
X-Slimpay-Timestamp: 1790000000
X-Slimpay-Signature: 9f2c...(hex hmac-sha256)

{"school_id":"SCH-9K2H7XQZ","student_id":"STU-2201"}

Invoice lookups send {"school_id": "...", "invoice_id": "INV-8841"}. LookupHandler verifies the signature, checks the timestamp is recent, parses the body and calls your code.

Student lookup

php
use Slimpay\School\Contracts\StudentLookup;

final class MyStudents implements StudentLookup
{
    public function findStudent(string $studentId): ?array
    {
        $s = Student::where('admission_no', $studentId)->first();

        if (!$s) {
            return null;                       // -> {"found": false}
        }

        return [
            'name'  => $s->full_name,          // shown to the payer
            'class' => $s->class_name,
            'guardian_phone' => $s->guardian_phone,
        ];
    }
}

$handler = new LookupHandler($secret, students: new MyStudents());
$body = $handler->handleStudent($rawBody, $headers);   // ['found' => true, 'student' => [...]]
  • Return null for unknown students. Do not throw.
  • Extra keys are stored against the payment and forwarded in the webhook as verified_student_data.
  • Student lookup is best-effort: if your endpoint is down or slower than 5 seconds, the payer can still pay with manually typed details.

Invoice lookup

php
use Slimpay\School\Contracts\InvoiceLookup;

final class MyInvoices implements InvoiceLookup
{
    public function findInvoice(string $invoiceId): ?array
    {
        $inv = Invoice::with('student')->where('number', $invoiceId)->first();
        if (!$inv) {
            return null;
        }

        return [
            'invoice' => [
                'invoice_id'  => $inv->number,
                'amount'      => $inv->balance,          // naira, required
                'description' => 'Third Term Tuition',
                'status'      => $inv->isPaid() ? 'paid' : 'unpaid',
            ],
            'student' => [
                'student_id' => $inv->student->admission_no,   // required
                'name'       => $inv->student->full_name,      // required
                'class'      => $inv->student->class_name,
                'email'      => $inv->student->guardian_email,
                'phone'      => $inv->student->guardian_phone,
            ],
        ];
    }
}
  • invoice.amount, student.student_id and student.name are required. If one is missing the SDK throws UnexpectedValueException.
  • status must be unpaid, pending or due for the invoice to be collectible; anything else fails with INVOICE_NOT_COLLECTIBLE.
  • The amount must be at least ₦100.
Keep it fast

The invoice lookup timeout is 8 seconds and a failure is a hard failure — there is no manual fallback.

Exceptions

ExceptionMeaningRespond with
InvalidSignatureExceptionNot from Slimpay, wrong secret, or timestamp too old401
MalformedRequestExceptionBody isn't the expected JSON, or that lookup isn't configured400
UnexpectedValueExceptionYour findInvoice() returned an incomplete arrayFix your code

Complete plain-PHP endpoint

php
<?php // student-lookup.php
require __DIR__ . '/vendor/autoload.php';

use Slimpay\School\LookupHandler;
use Slimpay\School\Exceptions\{InvalidSignatureException, MalformedRequestException};

$handler = new LookupHandler(getenv('SLIMPAY_STUDENT_LOOKUP_SECRET'), new MyStudents());

header('Content-Type: application/json');
try {
    echo json_encode($handler->handleStudent(file_get_contents('php://input'), getallheaders()));
} catch (InvalidSignatureException) {
    http_response_code(401); echo json_encode(['error' => 'unauthorized']);
} catch (MalformedRequestException) {
    http_response_code(400); echo json_encode(['error' => 'bad request']);
}

LookupHandler accepts a fourth constructor argument, tolerance (seconds, default 300), the maximum clock skew allowed. Keep your server clock synced with NTP rather than raising it.