usdpay / laravel
Official Laravel SDK for accepting USDT payments with USDPAY.
Requires
- php: ^8.2
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.8
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5|^12.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Accept USDT payments in Laravel applications.
Customers pay directly to your wallet. USDPAY confirms payments on-chain and sends signed webhooks.
Requirements
- PHP 8.2+
- Laravel 12 or Laravel 13
- A USDPAY store with a secret API key and webhook secret
Quick start
Install the package. Laravel discovers its service provider and facade automatically:
composer require usdpay/laravel
Add server-side credentials to .env:
USDPAY_SECRET=sk_live_... USDPAY_WEBHOOK_SECRET=...
Create an invoice with a stable idempotency key:
use Usdpay\Laravel\Facades\Usdpay; $invoice = Usdpay::createInvoice( [ 'amount' => '49.00', 'currency' => 'USD', 'orderId' => 'ORDER-1042', 'expiresInMinutes' => 30, 'returnUrl' => route('orders.show', 1042), ], idempotencyKey: 'ORDER-1042-create', ); return redirect()->away($invoice->checkoutUrl);
If network is omitted, the customer chooses TRC20, TON or BEP20 at USDPAY checkout. Monetary values are decimal strings and are never converted to floats.
Dependency injection
The facade is optional. Inject UsdpayManager into application services or controllers:
use Usdpay\Laravel\UsdpayManager; final class CheckoutController { public function __construct(private UsdpayManager $usdpay) {} public function __invoke(Order $order) { $invoice = $this->usdpay->createInvoice([ 'amount' => $order->total_decimal, 'currency' => $order->currency, 'orderId' => (string) $order->id, ], 'order-'.$order->id.'-create'); return redirect()->away($invoice->checkoutUrl); } }
Fetch an invoice by its unguessable ID:
$invoice = Usdpay::getInvoice('inv_7Fq2xK9'); if ($invoice->status === 'paid') { // Read-only status check. Fulfilment should still be idempotent. }
The Invoice DTO exposes documented fields as typed properties and preserves the complete API response in $invoice->raw for forward compatibility.
Signed webhook events
The package registers this route by default:
POST /usdpay/webhook
It verifies X-USDPAY-Signature against the original raw request body before decoding JSON. Valid invoice.paid and invoice.expired deliveries become Laravel events:
use Usdpay\Laravel\Events\InvoicePaid; final class ActivateOrder { public function handle(InvoicePaid $event): void { $invoice = $event->invoice; $idempotencyKey = $event->idempotencyKey; $deliveryId = $event->deliveryId; // Your application's idempotent business logic belongs here. } }
Register the listener using normal Laravel event discovery or your application's event configuration.
The package verifies and parses the delivery only. It never changes an Order, grants a subscription, credits a balance, refunds a payment or performs fulfilment automatically.
Production idempotency example
Signature verification proves that USDPAY sent the request. It does not make fulfilment idempotent. Store X-USDPAY-Idempotency-Key under a unique constraint and lock the order in one transaction:
use Illuminate\Support\Facades\DB; use Usdpay\Laravel\Events\InvoicePaid; public function handle(InvoicePaid $event): void { DB::transaction(function () use ($event): void { $processed = ProcessedWebhook::query()->firstOrCreate([ 'key' => $event->idempotencyKey, ]); if (! $processed->wasRecentlyCreated) { return; } $order = Order::query() ->where('external_id', $event->invoice->orderId) ->lockForUpdate() ->firstOrFail(); if ($order->paid_at !== null) { return; } $order->update(['paid_at' => now()]); }); }
Configuration
Publish the configuration when defaults need to be changed:
php artisan vendor:publish --tag=usdpay-config
Available environment variables:
USDPAY_SECRET=sk_live_... USDPAY_WEBHOOK_SECRET=... USDPAY_BASE_URL=https://usdpay.me USDPAY_TIMEOUT=10 USDPAY_CONNECT_TIMEOUT=5 USDPAY_WEBHOOK_ENABLED=true USDPAY_WEBHOOK_PATH=usdpay/webhook
Set USDPAY_WEBHOOK_ENABLED=false to disable automatic route registration. Configure the resulting HTTPS webhook URL in the corresponding USDPAY store.
API errors and retries
API and transport failures throw UsdpayApiException:
use Illuminate\Support\Facades\Log; use Usdpay\Laravel\Exceptions\UsdpayApiException; try { $invoice = Usdpay::createInvoice($payload, 'ORDER-1042-create'); } catch (UsdpayApiException $exception) { Log::warning('USDPAY request failed', [ 'status' => $exception->statusCode, 'code' => $exception->errorCode, 'request_id' => $exception->requestId, 'retry_after' => $exception->retryAfter, ]); }
The package performs at most two automatic retries for invoice creation on connection failures and HTTP 429, 500, 502, 503 or 504. Every attempt reuses the caller-provided Idempotency-Key; Retry-After is honored. Validation, authentication, authorization, not-found and conflict responses are never retried. Secrets and authorization headers are redacted from exceptions.
Security
- Keep
USDPAY_SECRETserver-side. Never expose it to JavaScript, Blade output or browser requests. - Use HTTPS callback URLs in production.
- Verify payment only from a signed
invoice.paidwebhook or authenticated server-side API state, never from a browser redirect. - Use
X-USDPAY-Idempotency-Keyand a database unique constraint before fulfilling an order. - Never log API keys, webhook secrets, raw authorization headers or wallet private keys.
- USDPAY is non-custodial. This package never needs a seed phrase or private key.
Supported networks
- USDT on TRON (
TRC20) - USDT on TON
- USDT on BNB Smart Chain (
BEP20)
Documentation
Using Node.js? See the official Node.js SDK.
License
MIT © 2026 PIXELTIDE LLC.