API Client
Slimpay\School\Client calls Slimpay on behalf of your school using your API key.
use Slimpay\School\Client;
$slimpay = new Client(
apiKey: getenv('SLIMPAY_API_KEY'), // sandbox or live
baseUrl: 'https://api.slimpay.ng/api/v1', // default, shown for clarity
);
A sandbox key hits the sandbox; a live key is real money. Keep the live key server-side only.
collectInvoice()
Start a payment for an invoice that lives in your system.
$checkout = $slimpay->collectInvoice(
schoolId: 'SCH-9K2H7XQZ',
invoiceId: 'INV-8841',
redirectUrl: 'https://portal.example.edu.ng/payments/return',
);
return redirect($checkout->url);
- Slimpay validates your key and
school_id. - Slimpay calls your invoice lookup for the amount and student.
- A checkout is created and returned. The payer pays, then returns to your
redirectUrl. - Slimpay sends a
payment.receivedwebhook.
Never mark an invoice paid from the redirect alone. Wait for the webhook.
The Checkout object
| Property | Meaning |
|---|---|
reference | Checkout reference (SCH-...); matches checkout_reference in the webhook |
url | Send the payer here |
invoiceId | Echo of your invoice id |
amount | Total the payer pays |
schoolReceives / platformFee | The split |
student | student_id, name, class as returned by your lookup |
expiresAt | ISO-8601; checkouts last 30 minutes |
Retrying is safe: calling collectInvoice() again for the same invoice while a checkout is unexpired returns the same checkout. redirectUrl is required and must be a valid URL.
Errors
Failures throw Slimpay\School\Exceptions\ApiException:
use Slimpay\School\Exceptions\ApiException;
try {
$checkout = $slimpay->collectInvoice(...);
} catch (ApiException $e) {
$e->getMessage(); // human-readable
$e->httpStatus; // 0 when Slimpay couldn't be reached
$e->errorCode; // machine-readable, may be null
$e->body; // full decoded response
}
| errorCode | HTTP | Meaning |
|---|---|---|
SETTLEMENT_PENDING | 422 | Settlement account not approved yet |
INVOICE_LOOKUP_NOT_CONFIGURED | 422 | No invoice lookup URL/secret saved |
INVOICE_NOT_FOUND | 404 | Your endpoint returned not-found, timed out or answered badly |
INVOICE_NOT_COLLECTIBLE | 422 | Invoice status isn't unpaid/pending/due |
INVOICE_COLLECT_LOCKED | 409 | Another request for this invoice is in flight; retry shortly |
| (none) | 401 | Missing or invalid API key |
| (none) | 403 | school_id doesn't belong to this key |
| (none) | 422 | Validation failure, or amount under ₦100 |
Rate limits apply to financial endpoints; back off and retry on HTTP 429.
Custom HTTP transport
By default the client uses ext-curl. To use Guzzle, Symfony HttpClient or a test double, pass a callable returning [statusCode, rawBody]:
$slimpay = new Client($key, transport: function (string $method, string $url, array $headers, ?string $body): array {
$res = $guzzle->request($method, $url, ['headers' => $headers, 'body' => $body, 'http_errors' => false]);
return [$res->getStatusCode(), (string) $res->getBody()];
});
docs