rocketgate/sdk
A Laravel/PHP SDK for integrating the RocketGate payment gateway, providing a clean, developer-friendly API for payments, subscriptions, customer vaulting, refunds, and secure transaction handling in your applications.
Install. The SDK ships as rocketgate/sdk, but with 14 stars and no dependents you should assume it is not a normal Packagist citizen. Try the straightforward path first:
composer require rocketgate/sdk
If that resolves to an ancient tag or fails, pin it through a VCS repository and lock to a commit:
"repositories": [{ "type": "vcs", "url": "https://github.com/rocketgate/rocketgate-php-sdk" }],
"require": { "rocketgate/sdk": "dev-master#<commit-sha>" }
If composer.json in the repo has no PSR-4 map (very likely — this is a classic RocketGate/*.php SDK with global classes and require_once), you have two options: add the directory to your root composer.json classmap, or copy the files into app/Services/RocketGate/ and classmap that folder. Do not hand-edit files inside vendor/.
Look first at:
RocketGateRequest.php — the constant list (MERCHANT_ACCOUNT, MERCHANT_PASSWORD, CARDNO, EXPIRE_MONTH, EXPIRE_YEAR, CVV2, AMOUNT, CURRENCY, MERCHANT_CUSTOMER_ID, MERCHANT_INVOICE_ID, CARD_HASH, …). This is your real API surface.RocketGateResponse.php — RESPONSE_CODE, REASON_CODE, TRANSACTION_ID, AUTH_NO, AVS_RESPONSE, CVV2_RESPONSE, CARD_HASH.RocketGateGateway.php — the Perform* methods (PerformPurchase, PerformAuth, PerformTicket, PerformVoid, PerformCredit, PerformRebill, PerformRebillUpdate, PerformRebillCancel, PerformCardScrub, PerformHostedPage, PerformThreeDSecure).test.php / examples/ file in the repo — that is the fastest working reference.Wire it into Laravel. Add config/rocketgate.php:
return [
'merchant_id' => env('ROCKETGATE_MERCHANT_ID'),
'merchant_password' => env('ROCKETGATE_MERCHANT_PASSWORD'),
'test_mode' => env('ROCKETGATE_TEST_MODE', true),
];
Bind a singleton in a service provider (or use #[Singleton] on the service):
$this->app->singleton(RocketGateService::class, fn ($app) => new RocketGateService(
config('rocketgate.merchant_id'),
config('rocketgate.merchant_password'),
config('rocketgate.test_mode'),
));
First use case — a sandbox purchase. Wrap the ceremony in one method so your controller only sees a DTO:
$request = new RocketGateRequest();
$request->Set(RocketGateRequest::MERCHANT_ACCOUNT, $this->merchantId);
$request->Set(RocketGateRequest::MERCHANT_PASSWORD, $this->merchantPassword);
$request->Set(RocketGateRequest::MERCHANT_CUSTOMER_ID, $order->user_id);
$request->Set(RocketGateRequest::MERCHANT_INVOICE_ID, $order->uuid);
$request->Set(RocketGateRequest::CARDNO, $dto->cardNumber);
$request->Set(RocketGateRequest::EXPIRE_MONTH, $dto->expMonth); // "09"
$request->Set(RocketGateRequest::EXPIRE_YEAR, $dto->expYear); // "2030"
$request->Set(RocketGateRequest::CVV2, $dto->cvv);
$request->Set(RocketGateRequest::AMOUNT, number_format($dto->amount, 2, '.', ''));
$request->Set(RocketGateRequest::CURRENCY, 'USD');
$response = new RocketGateResponse();
$gateway = new RocketGateGateway();
$gateway->SetTestMode($this->testMode); // switches sandbox vs production host
$gateway->PerformPurchase($request, $response);
if ($response->Get(RocketGateResponse::RESPONSE_CODE) === 0) {
// success — persist TRANSACTION_ID immediately
}
Use RocketGate's documented test card numbers against sandbox before writing any live code.
Service-layer wrapper is non-negotiable. Treat the SDK as a transport detail. One class (RocketGateService) owns RocketGateGateway, builds requests from your own DTOs, and returns your own PaymentResult value object (success, transactionId, authNo, responseCode, reasonCode, avs, cvv, cardHash, raw). Controllers, jobs, and listeners never touch RocketGateRequest.
Map your identifiers deliberately.
MERCHANT_CUSTOMER_ID → your users.id (stable, reused across rebills).MERCHANT_INVOICE_ID → your order UUID / unique attempt ID. Never reuse it for a retry of a different charge; RocketGate uses it for reconciliation and duplicate detection.TRANSACTION_ID, AUTH_NO, CARD_HASH, response/reason codes, and the full raw response JSON in a payment_transactions table on every call, including failures.Two-step auth then capture. For physical-goods flows, PerformAuth() then PerformTicket($request, $response) with the original TRANSACTION_ID set (RocketGateRequest::REFERENCE_GUID or TRANSACTION_ID depending on SDK version — check the constant map). Do the capture in a queued job with a dead-letter path, and auto-void uncaptured auths after your window.
Subscriptions and rebills. Create the initial purchase/rebill, store CARD_HASH and the RocketGate TRANSACTION_ID, then drive lifecycle with PerformRebillUpdate (amount/date changes), PerformRebillCancel, and a scheduled reconciliation command that queries rebill status. There are no true push webhooks in the classic protocol — your scheduler is the source of truth for "did the monthly charge land."
Tokenized repeat charges. After a successful first charge, use CARD_HASH for subsequent purchases instead of storing PANs. This keeps you out of heavy PCI scope and avoids re-collecting card data. Prefer PerformHostedPage when the customer must enter a card and you want RocketGate-hosted fields.
Idempotency and retries. Wrap the gateway call in your own retry policy keyed on MERCHANT_INVOICE_ID. On network exceptions or RESPONSE_CODE == 3 (timeout/unknown), mark the order pending — never failed — and reconcile via a lookup/status job before retrying. Blind retries with the same invoice ID can double-charge or be rejected as duplicates depending on gateway state.
Events over inline side effects. After persisting the result, dispatch PaymentSucceeded / PaymentFailed. Send receipt mail, provision access, and update subscriptions in listeners so a mail failure can't roll back a captured payment.
Testing. Bind a fake RocketGateService in the container for feature tests. For the real SDK, run an integration suite against sandbox behind a @group gateway tag, and use RocketGate's decline/3DS test cards to exercise the failure branches.
RocketGateGateway, not RocketGate\Gateway), require_once includes, and no PSR-4. If Laravel's package discovery fails, add a classmap entry — never rely on files autoload for these, it hides load-order bugs.RocketGateGateway, Request, and Response are carriers, not immutable messages. Instantiate fresh instances per operation; never cache a gateway in a singleton property across requests, and never reuse a Response for a second call.SetTestMode(true) swaps hosts, not credentials. You still need sandbox merchant ID/password. The most common "it works in test, 401 in prod" cause is a .env that kept test credentials with test mode off.RESPONSE_CODE is a string-ish value. Compare loosely (== 0) or cast to int; strict === 0 against a string "0" will silently fail. Also check REASON_CODE and presence of TRANSACTION_ID before declaring success.RESPONSE_CODE 3 means "unknown," not "declined." This is the classic payment-gateway trap. It covers timeouts and lost responses; treat as pending and reconcile."9.99", not cents and not floats), currency is uppercase ISO-4217, expiry month is two characters ("09"), year is four digits. number_format($x, 2, '.', '') avoids locale comma bugs.TRANSACTION_ID. Set a dedicated Monolog channel with a redaction processor, and make sure APP_DEBUG exceptions don't dump the request payload.error_log() on transport errors in older versions. If you see stray output breaking JSON responses, capture output buffering around the call or patch via a subclass, not by editing vendor files.PerformThreeDSecure requires a return/term URL and an additional customer round-trip; don't bolt it onto the standard purchase path without a dedicated state machine and a callback route.try-catch, keep it out of long DB transactions, and always persist a pending row before calling so a crash leaves a recoverable record.payment_transactions against RocketGate's transaction/rebill status for the last N days; with no webhooks, that job is your only defense against silent drift.RocketGateRequest mapping and the RocketGateResponse→PaymentResult mapping in two small dedicated classes. When RocketGate changes a constant or you need a new field, the blast radius stays in one file instead of leaking through your domain.How can I help you explore Laravel packages today?