Search by

usdpay / laravel

USDPAY

Official Laravel SDK for accepting USDT payments with USDPAY.

v1.0.0 2026-09-16 08:25 UTC

This package is auto-updated.

Last update: 2026-09-16 08:48:03 UTC


README

Packagist Version PHP Version Laravel Tests License

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_SECRET server-side. Never expose it to JavaScript, Blade output or browser requests.
  • Use HTTPS callback URLs in production.
  • Verify payment only from a signed invoice.paid webhook or authenticated server-side API state, never from a browser redirect.
  • Use X-USDPAY-Idempotency-Key and 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.