lahiru / laravel-solidgate
Laravel SDK for SolidGate — card & APM payments, subscriptions, webhooks, and reporting with official HMAC-SHA512 signing, typed responses, and smart API defaults.
Requires
- php: ^8.2
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.13
- orchestra/testbench: ^10.9|^11.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^11.5.3
README
Laravel package for the SolidGate payment gateway. Use the facade or dependency injection, get typed responses, and call 74+ API endpoints with correct HMAC-SHA512 signing and sensible defaults.
Good for: server-side card/APM charges, subscriptions, hosted checkout, embedded payment forms, webhooks, and reporting.
Table of Contents
Getting started
- Features
- Requirements
- Installation
- Configuration
- Choose your integration
- Using the package in Laravel
- Quick Start
Checkout (customer-facing)
Server-side API
Reference
- Responses & Error Handling
- Helper Classes
- Troubleshooting
- API Reference Map
- Development
- Changelog
- License & References
Features
| Feature | Description |
|---|---|
| 74+ endpoints | Card, APM, subscriptions, taxes, checkout, webhooks, reporting |
| Checkout docs | Payment Page and Payment Form with copy-paste Laravel examples |
| Correct signing | HMAC-SHA512 over exact JSON body — matches official PHP SDK |
| Smart defaults | Auto-fills platform, payment_type, and card expiry formatting |
| Type-safe responses | SolidGateResponse with dot-notation and error helpers |
| Webhook support | Signature verification middleware + Laravel events |
| Helper classes | Platform, PaymentType, RefundReason, currency utilities |
| Laravel native | HTTP client, service container, facade, config publishing |
Requirements
- PHP 8.2+
- Laravel 10.x, 11.x, 12.x, or 13.x (Laravel 13 requires PHP 8.3+)
Installation
composer require lahiru/laravel-solidgate
Publish the config (recommended):
php artisan vendor:publish --tag=solidgate-config
Copy environment variables from .env.example:
cp vendor/lahiru/laravel-solidgate/.env.example .env.example.solidgate
# Merge the SolidGate keys into your .env
Configuration
Get your keys from SolidGate Hub → Developers → Channel details:
| Key type | Prefix | Used for |
|---|---|---|
| API keys | api_pk_* / api_sk_* |
Outgoing API requests |
| Webhook keys | wh_pk_* / wh_sk_* |
Incoming webhook verification |
Environment variables
# ── Required ────────────────────────────────────────────── SOLIDGATE_PUBLIC_KEY=api_pk_your_public_key SOLIDGATE_SECRET_KEY=api_sk_your_secret_key # ── API URLs (defaults are production) ────────────────── SOLIDGATE_API_BASE_URL=https://pay.solidgate.com/api/v1/ SOLIDGATE_SUBSCRIPTIONS_BASE_URL=https://subscriptions.solidgate.com/api/v1/ SOLIDGATE_GATE_BASE_URL=https://gate.solidgate.com/api/ SOLIDGATE_REPORTS_BASE_URL=https://reports.solidgate.com/ SOLIDGATE_TIMEOUT=30 SOLIDGATE_VERIFY_SSL=true SOLIDGATE_LOG_REQUESTS=false # ── Payment defaults (applied when fields are omitted) ──── SOLIDGATE_DEFAULT_PLATFORM=WEB SOLIDGATE_DEFAULT_PAYMENT_TYPE=1-click # ── Webhooks (optional) ─────────────────────────────────── SOLIDGATE_WEBHOOK_ENABLED=false SOLIDGATE_WEBHOOK_PATH=solidgate/webhook SOLIDGATE_WEBHOOK_PUBLIC_KEY=wh_pk_your_webhook_public_key SOLIDGATE_WEBHOOK_SECRET=wh_sk_your_webhook_secret SOLIDGATE_SIGNATURE_HEADER=Signature SOLIDGATE_WEBHOOK_MIDDLEWARE=solidgate.webhook
Tip: Each API group uses a different base URL. Card payments go to
pay.solidgate.com, subscriptions tosubscriptions.solidgate.com, APM togate.solidgate.com, and reports toreports.solidgate.com. The package routes these automatically — you only call the facade methods.
Config file (config/solidgate.php)
After publishing, keys are read from config('solidgate.public_key') and config('solidgate.secret_key') (backed by SOLIDGATE_* env vars).
Choose your integration
Pick the flow that matches your product. All options below use this package on the server; only Payment Form also needs frontend JS.
| Integration | Customer experience | Package methods | Best when |
|---|---|---|---|
| Payment Page | Redirect to Solidgate-hosted page | createPaymentPage(), deactivatePaymentPage() |
Fastest setup, minimal frontend |
| Payment Form | Card fields on your site | generateSignature() + app helper for merchantData |
Full UI control, no redirect |
Card API (charge) |
You collect PAN (PCI scope) | charge(), auth(), recurring() |
Full backend control |
| APM | PayPal, Pix, etc. | initializeAlternativePayment() |
Alternative payment methods |
| Subscriptions | Recurring billing | retrieveSubscription(), cancelSubscription(), … |
SaaS / memberships |
Using the package in Laravel
Facade (typical)
use Lahiru\LaravelSolidGate\Facades\SolidGate; $response = SolidGate::charge([...]);
Dependency injection (testable)
use Lahiru\LaravelSolidGate\Contracts\SolidGateClientInterface; public function __construct( protected SolidGateClientInterface $solidgate ) {} $this->solidgate->charge([...]);
Signing helper (Payment Form)
$signature = SolidGate::generateSignature($jsonPayload);
Uses the same HMAC-SHA512 algorithm as outbound API requests and webhook verification.
Quick Start
Three-minute path to a successful server-side charge. For hosted or embedded checkout, jump to Checkout integrations.
1. Make your first charge
use Lahiru\LaravelSolidGate\Facades\SolidGate; use Lahiru\LaravelSolidGate\Support\Platform; $response = SolidGate::charge([ 'amount' => 10000, // $100.00 in cents 'currency' => 'USD', 'order_id' => (string) Str::uuid(), 'order_description' => 'Premium package', 'customer_email' => 'customer@example.com', 'ip_address' => $request->ip(), 'platform' => Platform::WEB, // WEB | MOB | APP 'card_number' => '4111111111111111', 'card_holder' => 'John Doe', 'card_exp_month' => '12', 'card_exp_year' => 2030, 'card_cvv' => '123', ]); if ($response->isSuccessful()) { $status = $response->get('order.status'); // e.g. "processing", "settle_ok" } else { $error = $response->getErrorMessage(); }
platform and payment_type are auto-filled from config when omitted. Card expiry fields are normalized automatically (3 → "03", year cast to integer).
2. Full controller example
use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Str; use Lahiru\LaravelSolidGate\Contracts\SolidGateClientInterface; use Lahiru\LaravelSolidGate\Support\Platform; class PaymentController extends Controller { public function __construct( protected SolidGateClientInterface $solidgate ) {} public function charge(Request $request): JsonResponse { $response = $this->solidgate->charge([ 'amount' => $request->integer('amount'), 'currency' => $request->string('currency'), 'order_id' => (string) Str::uuid(), 'order_description' => $request->string('order_description'), 'customer_email' => $request->string('customer_email'), 'ip_address' => $request->ip(), 'platform' => Platform::WEB, 'card_number' => $request->string('card_number'), 'card_holder' => $request->string('card_holder'), 'card_exp_month' => $request->string('card_exp_month'), 'card_exp_year' => $request->integer('card_exp_year'), 'card_cvv' => $request->string('card_cvv'), ]); if (! $response->isSuccessful()) { return response()->json([ 'error' => $response->getError(), 'message' => $response->getErrorMessage(), ], 422); } return response()->json([ 'status' => $response->get('order.status'), 'order' => $response->get('order'), ]); } }
3. Recurring / token payment
use Lahiru\LaravelSolidGate\Support\PaymentType; $response = SolidGate::recurring([ 'amount' => 10000, 'currency' => 'USD', 'order_id' => (string) Str::uuid(), 'customer_email' => 'customer@example.com', 'ip_address' => $request->ip(), 'payment_type' => PaymentType::RECURRING, 'recurring_token' => 'token-from-previous-payment', ]);
Checkout integrations
Customer-facing checkout using Solidgate UI. For server-side card capture without Solidgate JS, see Card Payments.
| Payment Page | Payment Form | |
|---|---|---|
| Docs | Payment Page | Payment Form |
| UX | Redirect to hosted URL | Embedded on your page |
| Frontend | None required | solid-form.js + PaymentFormSdk.init() |
| Backend | createPaymentPage() |
generateSignature() + encrypt paymentIntent |
| PCI | Card data on Solidgate | Card data tokenized by Solidgate iframe |
Payment Page (hosted)
When to use: you want checkout live quickly with almost no frontend work.
Flow
- Laravel calls
SolidGate::createPaymentPage(['order' => [...], 'page_customization' => [...]]). - API returns a
url(expires in ~24 hours). - Redirect the customer with
redirect()->away($url). - After payment, Solidgate sends the user to your
success_urlorfail_url.
API
| Method | Endpoint | Purpose |
|---|---|---|
createPaymentPage($attributes) |
POST /init |
Create hosted page, get URL |
deactivatePaymentPage($pageId) |
POST /deactivate |
Invalidate page before expiry |
Minimal example
use Illuminate\Support\Str; use Lahiru\LaravelSolidGate\Facades\SolidGate; use Lahiru\LaravelSolidGate\Support\Platform; $response = SolidGate::createPaymentPage([ 'order' => [ 'order_id' => (string) Str::uuid(), 'amount' => 10000, 'currency' => 'USD', 'order_description' => 'Premium package', 'customer_email' => $request->user()->email, 'ip_address' => $request->ip(), 'platform' => Platform::WEB, 'success_url' => route('checkout.success'), 'fail_url' => route('checkout.fail'), ], ]); if (! $response->isSuccessful()) { return back()->withErrors(['payment' => $response->getErrorMessage()]); } return redirect()->away($response->get('url'));
Controller + route
// app/Http/Controllers/PaymentPageController.php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Str; use Lahiru\LaravelSolidGate\Facades\SolidGate; use Lahiru\LaravelSolidGate\Support\Platform; class PaymentPageController extends Controller { public function checkout(Request $request) { $response = SolidGate::createPaymentPage([ 'order' => [ 'order_id' => (string) Str::uuid(), 'amount' => $request->integer('amount'), 'currency' => $request->string('currency'), 'order_description' => $request->string('description'), 'customer_email' => $request->user()->email, 'ip_address' => $request->ip(), 'platform' => Platform::WEB, 'success_url' => route('checkout.success'), 'fail_url' => route('checkout.fail'), ], ]); if (! $response->isSuccessful()) { return back()->withErrors(['payment' => $response->getErrorMessage()]); } return redirect()->away($response->get('url')); } }
// routes/web.php Route::get('/checkout', [PaymentPageController::class, 'checkout'])->name('checkout.start');
Subscriptions / catalog: use product_price_id in order (from SolidGate::getProductPrices()). See Create your payment page.
Checklist
- Unique
order_idper checkout attempt - Public
ip_address(not127.0.0.1in production) -
success_urlandfail_urlregistered and reachable - Store
idfrom response if you needdeactivatePaymentPage()later
Payment Form (embedded)
When to use: checkout must match your site design and stay on the same URL.
Flow
- Build a
paymentIntentarray (amount, currency,order_id, customer, URLs, etc.). - Server returns
merchantData:merchant,signature,paymentIntent(encrypted). - Blade loads
https://cdn.solidgate.com/js/solid-form.jsand callsPaymentFormSdk.init({ merchantData }).
merchantData shape (passed to JS)
| Key | Source |
|---|---|
merchant |
config('solidgate.public_key') |
signature |
SolidGate::generateSignature($json) |
paymentIntent |
AES-256-CBC encrypted JSON (see helper below) |
App helper — copy to app/Services/SolidgatePaymentForm.php (no extra Composer package):
<?php namespace App\Services; use Lahiru\LaravelSolidGate\Facades\SolidGate; class SolidgatePaymentForm { public function merchantData(array $paymentIntent): array { $json = json_encode($paymentIntent, JSON_UNESCAPED_SLASHES); return [ 'merchant' => config('solidgate.public_key'), 'signature' => SolidGate::generateSignature($json), 'paymentIntent' => $this->encrypt($paymentIntent, config('solidgate.secret_key')), ]; } private function encrypt(array $paymentIntent, string $secretKey): string { $payload = json_encode($paymentIntent, JSON_UNESCAPED_SLASHES); $key = substr($secretKey, 0, 32); $ivLen = openssl_cipher_iv_length('aes-256-cbc'); $iv = openssl_random_pseudo_bytes($ivLen); $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); return str_replace(['+', '/'], ['-', '_'], base64_encode($iv.$encrypted)); } }
Encryption matches Solidgate’s without-SDK PHP guide.
Controller
namespace App\Http\Controllers; use App\Services\SolidgatePaymentForm; use Illuminate\Http\Request; use Illuminate\Support\Str; use Lahiru\LaravelSolidGate\Support\Platform; class PaymentFormController extends Controller { public function __construct(protected SolidgatePaymentForm $paymentForm) {} public function checkout(Request $request) { $paymentIntent = [ 'order_id' => (string) Str::uuid(), 'amount' => 10000, 'currency' => 'USD', 'order_description' => 'Premium package', 'customer_email' => $request->user()->email, 'ip_address' => $request->ip(), 'platform' => Platform::WEB, 'success_url' => route('checkout.success'), 'fail_url' => route('checkout.fail'), ]; return view('checkout.payment-form', [ 'merchantData' => $this->paymentForm->merchantData($paymentIntent), ]); } }
Field reference: paymentIntent object.
Blade
<div id="solid-payment-form-container"></div> <script src="https://cdn.solidgate.com/js/solid-form.js"></script> <script> PaymentFormSdk.init({ merchantData: @json($merchantData), formParams: { formTypeClass: 'default' }, }); </script>
Checklist
- Never expose
SOLIDGATE_SECRET_KEYto the browser - New
order_idon every payment attempt - Public
ip_address - Load
solid-form.jsonly once (duplicate script causes init warnings) - Dynamic amount/plan changes: update payment form
Optional: Official
solidgate/php-sdkexposes$api->formMerchantData($paymentIntent)if you prefer not to maintain the encrypt helper.
Card Payments
Server-side card processing (you send PAN/CVV from your backend). For Solidgate-hosted or embedded UI instead, see Checkout integrations.
All card endpoints use the pay API (pay.solidgate.com/api/v1/).
Required fields for charge()
| Field | Type | Example | Notes |
|---|---|---|---|
amount |
integer | 10000 |
Minor units (cents for USD) |
currency |
string | "USD" |
ISO 4217 |
order_id |
string | UUID | Must be unique per attempt |
order_description |
string | "Premium plan" |
|
customer_email |
string | "user@mail.com" |
|
ip_address |
string | "203.0.113.0" |
Public IP only — see Troubleshooting |
platform |
string | "WEB" |
WEB, MOB, or APP |
card_number |
string | "4111…" |
Full PAN, 12–19 digits |
card_holder |
string | "John Doe" |
Name on card |
card_exp_month |
string | "12" |
Zero-padded automatically |
card_exp_year |
integer | 2030 |
4-digit year |
card_cvv |
string | "123" |
Required for first payment |
For token payments, omit card fields and pass payment_type + recurring_token instead.
Available methods
// ── Process payments ────────────────────────────────────── SolidGate::charge([...]); // Charge card SolidGate::auth([...]); // Authorize only (no capture) SolidGate::recurring([...]); // Token-based charge SolidGate::resignTransaction([...]); // Re-sign expired token SolidGate::chargeWithGooglePay([...]); SolidGate::chargeWithApplePay([...]); SolidGate::createIncrementalAuth([ 'order_id' => 'order-123', 'amount' => 500, ]); // ── Post-payment operations ─────────────────────────────── SolidGate::status(['order_id' => 'order-123']); SolidGate::getOrderStatus('order-123'); SolidGate::refund(['order_id' => 'order-123', 'amount' => 5000]); SolidGate::void(['order_id' => 'order-123']); SolidGate::settle(['order_id' => 'order-123', 'amount' => 10000]); SolidGate::getArnCodes(['order_id' => 'order-123']); // ── Refunds with reason codes ───────────────────────────── use Lahiru\LaravelSolidGate\Support\RefundReason; SolidGate::processFullRefund('order-123', 5000, 'card', RefundReason::REQUEST_BY_USER); SolidGate::processPartialRefund('order-123', 2500, 'card', RefundReason::REQUEST_BY_USER);
Alternative Payments (APM)
APM endpoints use the gate API (gate.solidgate.com/api/), not the pay API.
use Lahiru\LaravelSolidGate\Support\Platform; // Start payment (PayPal, Pix, etc.) $response = SolidGate::initializeAlternativePayment([ 'payment_method' => 'paypal-vault', 'order_id' => 'order-123', 'amount' => 1020, 'currency' => 'USD', 'customer_email' => 'customer@example.com', 'order_description' => 'Premium package', 'ip_address' => $request->ip(), 'platform' => Platform::WEB, ]); // Token-based APM recurring SolidGate::recurringAlternativePayment([ 'order_id' => 'order-123', 'amount' => 1020, 'currency' => 'USD', 'payment_method' => 'paypal-vault', 'token' => 'token-from-previous-payment', ]); // Status, revoke, refund SolidGate::getAlternativePaymentOrderStatus('order-123'); SolidGate::revokeRecurringToken(['token' => 'token-value']); SolidGate::processFullRefund('order-123', 1000, 'paypal');
Note: Card recurring uses
recurring_token. APM recurring usestoken. These are different field names per SolidGate API spec.
Subscriptions
All subscription endpoints use subscriptions.solidgate.com/api/v1/.
use Lahiru\LaravelSolidGate\Support\CancelSubscriptionReason; // Read & update SolidGate::retrieveSubscription($subscriptionId); SolidGate::getSubscriptionList($customerId); SolidGate::updateSubscription($subscriptionId, ['product_id' => $newProductId]); SolidGate::switchSubscriptionProduct($subscriptionId, $newProductId); SolidGate::updatePaymentMethodToken($subscriptionId, $token); // Cancel & restore SolidGate::cancelSubscription($subscriptionId, CancelSubscriptionReason::CANCELLATION_BY_CUSTOMER); SolidGate::cancelSubscriptionsByCustomer($customerId, CancelSubscriptionReason::CANCELLATION_BY_CUSTOMER); SolidGate::restoreSubscription($subscriptionId, $expireDate); // Pause schedule SolidGate::createSubscriptionPause($subscriptionId, '2026-12-31', '2026-06-01'); SolidGate::updateSubscriptionPause($subscriptionId, [...]); SolidGate::removeSubscriptionPause($subscriptionId); // Invoices & orders SolidGate::listInvoicesBySubscription($subscriptionId); SolidGate::listOrdersByInvoice($invoiceId);
Products, Taxes & Reporting
// Products & prices SolidGate::createProduct([...]); SolidGate::getProductList(['filter' => ['status' => 'active']]); SolidGate::getProduct($productId); SolidGate::updateProduct($productId, [...]); SolidGate::archiveProduct($productId); SolidGate::createProductPrice($productId, [...]); SolidGate::getProductPrices($productId); SolidGate::calculateProductPrice(['product_id' => $productId, 'currency' => 'USD']); // Taxes (async: create report, then download by report_id) $response = SolidGate::createTransactionalTax([ 'date_from' => '2025-01-15 11:00:00', 'date_to' => '2025-06-20 13:00:00', ]); SolidGate::downloadTransactionalTax('TAX_250702_140728_CHECKOUT'); // Reports (async: generate, then download) SolidGate::getCardOrdersReport(['date_from' => '...', 'date_to' => '...']); SolidGate::getApmOrdersReport([...]); SolidGate::getSubscriptionsReport([...]); SolidGate::getChargebacksReport([...]); SolidGate::downloadFinancialEntries($reportId); SolidGate::getRoutingEventsReport([...]); SolidGate::downloadRoutingEvents($reportId); // Payment links (shareable URL, separate from Payment Page) SolidGate::createPaymentLink([...]); SolidGate::deactivatePaymentLink($linkId); // Hosted / embedded checkout: [Checkout integrations](#checkout-integrations) // Risks & files SolidGate::createFraudPreventionListItems(['items' => [...]]); SolidGate::createDisputeRepresentment([...]); SolidGate::createFile(['file_name' => 'document.pdf', 'file_type' => 'application/pdf', 'file_size' => 1024000]);
Webhooks
Receive async events (card_gate.order.updated, chargebacks, etc.) on a Laravel route with signature verification.
Setup
SOLIDGATE_WEBHOOK_ENABLED=true SOLIDGATE_WEBHOOK_PATH=solidgate/webhook SOLIDGATE_WEBHOOK_PUBLIC_KEY=wh_pk_your_webhook_public_key SOLIDGATE_WEBHOOK_SECRET=wh_sk_your_webhook_secret
The package registers POST /solidgate/webhook with signature verification middleware.
Exclude from CSRF (Laravel 11+):
// bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ 'solidgate/webhook', ]); })
Incoming headers
| Header | Description |
|---|---|
solidgate-event-type |
Event name, e.g. card_gate.order.updated |
solidgate-event-id |
Unique event ID |
Signature |
HMAC signature of raw request body |
Merchant |
Webhook public key |
Handle events
use Lahiru\LaravelSolidGate\Events\SolidGateWebhookReceived; // app/Providers/EventServiceProvider.php (or AppServiceProvider) protected $listen = [ SolidGateWebhookReceived::class => [ ProcessSolidGateWebhook::class, ], ];
// app/Listeners/ProcessSolidGateWebhook.php public function handle(SolidGateWebhookReceived $event): void { match ($event->eventType) { 'card_gate.order.updated' => $this->handleOrderUpdated($event->payload), 'card_gate.chargeback.received' => $this->handleChargeback($event->payload), default => null, }; }
Manual signature verification
use Lahiru\LaravelSolidGate\Support\SignatureValidator; SignatureValidator::validate( $publicKey, $request->getContent(), $secretKey, $request->header('Signature') );
Responses & Error Handling
SolidGate has two types of errors. Handle both:
| Type | HTTP status | How to detect |
|---|---|---|
| Validation / business error | 200 with error object |
! $response->isSuccessful() |
| Transport / server error | 4xx / 5xx |
SolidGateApiException thrown |
use Lahiru\LaravelSolidGate\Exceptions\SolidGateApiException; use Lahiru\LaravelSolidGate\Exceptions\SolidGateConfigurationException; try { $response = SolidGate::charge([...]); if (! $response->isSuccessful()) { // HTTP 200 but SolidGate returned an error object return response()->json([ 'error' => $response->getError(), // ['code' => '2.01', 'messages' => [...]] 'message' => $response->getErrorMessage(), // "platform: Platform is empty or invalid" ], 422); } // Success $order = $response->get('order'); $status = $response->get('order.status'); } catch (SolidGateApiException $e) { // HTTP 4xx/5xx or connection timeout logger()->error('SolidGate API error', [ 'message' => $e->getMessage(), 'response' => $e->getResponse(), 'code' => $e->getCode(), ]); } catch (SolidGateConfigurationException $e) { logger()->error('SolidGate not configured', ['message' => $e->getMessage()]); }
Response helpers
$response->isSuccessful(); // true only when HTTP 2xx AND no error object $response->hasError(); // true when error object is present $response->getError(); // raw error array $response->getErrorMessage(); // flattened human-readable string $response->get('order.status'); // dot-notation access $response->toArray(); $response->toJson(); $response->statusCode;
Helper Classes
Platform — customer device
use Lahiru\LaravelSolidGate\Support\Platform; Platform::WEB; // Desktop browser Platform::MOB; // Mobile browser Platform::APP; // Native app
PaymentType — CIT / MIT classification
use Lahiru\LaravelSolidGate\Support\PaymentType; PaymentType::ONE_CLICK; // Customer-initiated (first payment) PaymentType::RECURRING; // Subscription MIT PaymentType::RETRY; // Reattempt MIT PaymentType::INSTALLMENT; // Installment MIT PaymentType::REBILL; // Unscheduled MIT PaymentType::MOTO; // Mail/phone order (no card_cvv)
SolidGateConstants — currency formatting
use Lahiru\LaravelSolidGate\Support\SolidGateConstants; SolidGateConstants::isZeroDecimalCurrency('JPY'); // true SolidGateConstants::formatAmount(99.99, 'USD'); // 9999 (cents) SolidGateConstants::parseAmount(9999, 'USD'); // 99.99
RefundReason / CancelSubscriptionReason
Official reason codes — see Refund Reasons and Cancel Codes.
Troubleshooting
Payment Page or Form fails to load
| Issue | Fix |
|---|---|
| Form blank / init error | New order_id, public ip_address, required paymentIntent fields |
Invalid IP on checkout |
Use customer public IP in production; see below |
| Payment Form script warning | Load solid-form.js only once |
| Page URL expired | Links last ~24h; call createPaymentPage() again |
Platform is empty or invalid (error 2.01)
Add platform to your request or rely on the config default:
'platform' => Platform::WEB, // or MOB, APP
Config default: SOLIDGATE_DEFAULT_PLATFORM=WEB
Invalid IP — private IP rejected
SolidGate rejects private IPs (127.0.0.1, 192.168.x.x, etc.). When testing locally:
'ip_address' => '8.8.8.8', // sandbox only — use real client IP in production
In production, always pass the customer's public IP from the frontend or a trusted proxy header.
HTTP 200 but payment failed
SolidGate returns HTTP 200 with an error object for validation failures. Always check isSuccessful() — do not rely on HTTP status alone.
if (! $response->isSuccessful()) { logger()->warning('SolidGate validation error', [ 'code' => $response->get('error.code'), 'message' => $response->getErrorMessage(), ]); }
Wrong API base URL
| Symptom | Fix |
|---|---|
| Subscription call hits pay API | Use SolidGate::retrieveSubscription() — routes automatically |
| APM call fails with wrong host | Use initializeAlternativePayment() — uses gate API |
| Custom endpoint needed | Use SolidGate::send(), gate(), or subscriptions() |
// Direct access when no helper exists SolidGate::send('charge', $attributes); // pay API SolidGate::subscriptions('subscription/status', ['subscription_id' => $id]); SolidGate::gate('v1/status', ['order_id' => $orderId]); // gate API
Enable request logging
SOLIDGATE_LOG_REQUESTS=true
Logs URL, method, status, and response to Laravel's log channel at debug level.
API Reference Map
| Category | Base URL | Key methods |
|---|---|---|
| Card payments | pay.solidgate.com/api/v1/ |
charge, auth, recurring, refund, void, settle, status |
| Alternative payments | gate.solidgate.com/api/ |
initializeAlternativePayment, recurringAlternativePayment |
| Subscriptions | subscriptions.solidgate.com/api/v1/ |
retrieveSubscription, cancelSubscription, createProduct |
| Taxes | subscriptions.solidgate.com/api/v1/ |
createTransactionalTax, downloadTransactionalTax |
| Reporting | reports.solidgate.com/ |
getCardOrdersReport, getRoutingEventsReport |
| Checkout (hosted page) | pay.solidgate.com/api/v1/ |
createPaymentPage, deactivatePaymentPage |
| Checkout (payment link) | pay.solidgate.com/api/v1/ |
createPaymentLink, deactivatePaymentLink |
| Payment Form signing | — (local) | generateSignature() + app encrypt helper — see Payment Form |
| Webhooks | pay.solidgate.com/api/v1/ |
createWebhookEndpoint, listWebhookEndpoints |
Full API spec: api-docs.solidgate.com
Development
git clone https://github.com/Lprabodha/laravel-solidgate.git cd laravel-solidgate composer install cp .env.example .env # never commit real keys
composer test # PHPUnit composer analyse # PHPStan static analysis composer format # fix code style (Laravel Pint) composer format:check # verify code style without fixing
CI runs on every push and pull request via GitHub Actions:
| Job | Checks |
|---|---|
| tests | PHPUnit on PHP 8.2 (Laravel 12) and PHP 8.3 (Laravel 13) |
| static-analysis | PHPStan level 5 |
| code-style | Laravel Pint |
| security | Composer audit (advisory) |
Changelog
See CHANGELOG.md for full history.
1.0.2 — APM gate endpoints, PaymentType/Platform helpers, error formatting, routing reports.
1.0.1 — HMAC signing fix, endpoint path corrections, webhook validation, unit tests.
License & References
MIT — see LICENSE.
| Resource | Link |
|---|---|
| API Reference | api-docs.solidgate.com |
| Access & Signing | docs.solidgate.com/payments/integrate/access-to-api |
| Payment Guide | docs.solidgate.com |
| Payment Page | docs.solidgate.com/payments/integrate/payment-page |
| Payment Form | docs.solidgate.com/payments/integrate/payment-form |
| Refund Reasons | docs.solidgate.com/payments/payments-insights/refund-reasons |
| Cancel Codes | docs.solidgate.com/billing/subscription-overview/subscription-insights/subscription-cancel-codes |