wemisc / pay-sdk
Official PHP client for the WeMisc Pay partner integration and dashboard/mobile APIs.
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.8
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
- illuminate/support: Required only if you use the optional Laravel ServiceProvider/Facade (src/Laravel/*) — not needed for the plain PHP client.
README
The official WeMisc Pay PHP SDK. The Composer package name is
wemisc/pay-sdk. It covers both WeMisc Pay APIs with typed results and
exceptions instead of hand-rolled HTTP calls:
WeMiscPayClient— the partner integration API (api_token, server-to-server): create a checkout, confirm an invoice's status. This is what most integrations need.WeMiscPayDashboardClient— the dashboard/mobile API (per-user login): company profile, invoice/payment-session listing, reports. Use this to build a mobile app or an external dashboard on top of the same data a user sees when they log into WeMisc Pay.
Install
composer require wemisc/pay-sdk
Partner integration — WeMiscPayClient
use WeMiscPay\Sdk\WeMiscPayClient; use WeMiscPay\Sdk\Exceptions\ValidationException; use WeMiscPay\Sdk\Exceptions\ApiException; $client = new WeMiscPayClient( apiToken: 'wm_...', // Companies > Edit in the WeMiscPay dashboard baseUrl: 'https://your-wemisc-pay-instance.test/api/v1/integrations', ); try { $checkout = $client->checkout( amount: 250.00, successUrl: 'https://your-app.test/orders/123/paid', failUrl: 'https://your-app.test/orders/123/failed', reference: 'order-123', // your own id, echoed back later ); // Send the customer here — WeMiscPay hosts the actual card entry page. header("Location: {$checkout->checkoutUrl}"); } catch (ValidationException $e) { // $e->errors() is a field => [messages] map, same shape as Laravel validation errors. } catch (ApiException $e) { // e.g. 503 — no payment gateway configured on the WeMiscPay side yet. // $e->statusCode(), $e->body() }
Laravel
WEMISC_PAY_API_TOKEN=wm_...
WEMISC_PAY_BASE_URL=https://your-wemisc-pay-instance.test/api/v1/integrations
use WeMiscPay\Sdk\Laravel\Facades\WeMiscPay; $checkout = WeMiscPay::checkout(250.00, route('orders.paid', $order), route('orders.failed', $order), (string) $order->id); return redirect($checkout->checkoutUrl);
Handling the redirect back
Once the customer finishes on checkout_url, WeMiscPay redirects their browser back to your success_url or fail_url with ?invoice_id=... appended (&status=... too, on the success and explicit-cancel paths — a generic failure only appends invoice_id).
Don't trust those query params as proof of payment — they're for UX (which page to show), not confirmation. Always re-check the real state server-side:
$invoice = $client->getInvoice((int) $request->query('invoice_id')); if ($invoice->isPaid()) { // fulfil the order }
Dashboard / mobile — WeMiscPayDashboardClient
A separate API, authenticated by logging in as a WeMiscPay user (Sanctum token), not the company api_token above. A main-account user sees every company through it; everyone else sees only their own — exactly like the web dashboard.
use WeMiscPay\Sdk\WeMiscPayDashboardClient; $dashboard = new WeMiscPayDashboardClient('https://your-wemisc-pay-instance.test/api'); $dashboard->login('you@company.test', 'your-password'); // stores the token on $dashboard for you $profile = $dashboard->companyProfile(); echo $profile->name, ' — balance: ', $profile->balance; foreach ($profile->paymentProfiles as $method) { echo "{$method->paymentMethod}: {$method->successCount} successful, {$method->commissionTotal} commission\n"; } $page = $dashboard->invoices(); // DTO\PaginatedResult of DTO\DashboardInvoice foreach ($page->items as $invoice) { echo "{$invoice->invoiceSerial}: {$invoice->status}\n"; } $one = $dashboard->invoice(42); $sessions = $dashboard->paymentSessions(); $rows = $dashboard->monthlyPaidPerCompany(); // raw arrays — see "Reports" below $dashboard->logout();
Already have a token from a previous login() (e.g. you persisted it in the current user's session)? Skip logging in again:
$dashboard = (new WeMiscPayDashboardClient($baseUrl))->withToken($storedToken);
Laravel
WEMISC_PAY_DASHBOARD_BASE_URL=https://your-wemisc-pay-instance.test/api
use WeMiscPay\Sdk\Laravel\Facades\WeMiscPayDashboard; WeMiscPayDashboard::login($request->email, $request->password); $profile = WeMiscPayDashboard::companyProfile();
Note this facade resolves a request-scoped instance (Application::scoped(), not a plain singleton) — safe under Octane/queue workers, where a plain singleton could otherwise leak one user's logged-in token into another request.
Reports
monthlyPaidPerCompany(), monthlyPaidPerBank(), settledPerCompany(), companyWithBanks() return plain decoded arrays, not DTOs — each groups rows differently (by company+month, bank+month, company+batch, company+bank), so a single fixed shape doesn't fit all four honestly. Check the field names against the in-dashboard API docs #mobile-reports section, or just var_dump() a response once.
API surface
WeMiscPayClient (partner integration, api_token):
| Method | Maps to | Returns |
|---|---|---|
checkout(amount, successUrl, failUrl, reference?) |
POST /checkout |
DTO\CheckoutResult |
getInvoice(invoiceId) |
GET /invoices/{id} |
DTO\Invoice |
WeMiscPayDashboardClient (dashboard/mobile, user login):
| Method | Maps to | Returns |
|---|---|---|
login(email, password) |
POST /login |
string (token, also stored on the client) |
withToken(token) |
— | $this, for reusing an existing token |
logout() |
POST /logout |
void |
companyProfile() |
GET /company/profile |
DTO\CompanyProfile |
invoices(page = 1) |
GET /invoices |
DTO\PaginatedResult<DTO\DashboardInvoice> |
invoice(invoiceId) |
GET /invoices/{id} |
DTO\DashboardInvoice |
paymentSessions(page = 1) |
GET /payment-sessions |
DTO\PaginatedResult<DTO\PaymentSession> |
monthlyPaidPerCompany() |
GET /reports/monthly-paid-company |
array |
monthlyPaidPerBank() |
GET /reports/monthly-paid-banks |
array |
settledPerCompany() |
GET /reports/settled-per-company |
array |
companyWithBanks() |
GET /reports/company-with-banks |
array |
Exceptions
Both clients throw the same set, all extending WeMiscPay\Sdk\Exceptions\WeMiscPayException:
AuthenticationException— invalid/missing credentials (401).ValidationException— bad input (422);->errors()gives the field-level messages.ApiException— anything else non-2xx (404, 503, ...);->statusCode()/->body().
WeMiscPayDashboardClient also throws a plain WeMiscPayException if you call an authenticated method before login()/withToken().
Testing this package
composer install
composer test