Skip to content

Nass Pay

Nass Pay is a hosted-checkout gateway: you create a transaction server-side, then send the customer to a Nass-hosted page to pay. charge() returns a redirectUrl and nothing else.

Credentials

Every key below lives under gateways.nass in config/parakit.php.

Config keyEnv varDefaultRequiredWhat it is
base_urlNASS_BASE_URLhttps://uat-gateway.nass.iq:9746NoNass API host. Note the :9746 port — it is part of the URL and must stay. Switch to the production host Nass gives you when you go live.
usernameNASS_USERNAMEYesMerchant login username. Issued by Nass when your account is set up.
passwordNASS_PASSWORDYesMerchant login password. Issued by Nass. Used to fetch a bearer token.
token_ttlNASS_TOKEN_TTL3000NoSeconds the fetched access token is cached. The cache expires 60s early, with a 30s floor.
transaction_typeNASS_TRANSACTION_TYPE1NoNass transaction type sent on every charge. Leave at 1 unless Nass tells you otherwise.
callback_urlNASS_CALLBACK_URLNoServer-to-server notification URL. Used as the default notifyUrl when a charge does not pass one.
return_urlNASS_RETURN_URLNoBrowser return URL after checkout. Used as the default backRef when a charge does not pass one.

.env example

env
NASS_BASE_URL=https://uat-gateway.nass.iq:9746
NASS_USERNAME=your-merchant-username
NASS_PASSWORD=your-merchant-password
NASS_TOKEN_TTL=3000
NASS_TRANSACTION_TYPE=1
NASS_CALLBACK_URL=https://your-app.test/payments/webhooks/nass
NASS_RETURN_URL=https://your-app.test/checkout/return

Payment flow

Charge an order:

php
use Froshly\Parakit\Facades\Payment;
use Froshly\Parakit\Enums\Currency;

$response = Payment::driver('nass')
    ->for($order)
    ->amount(25_000, Currency::IQD)   // 25,000 IQD — IQD is whole dinars
    ->description('Order #1042')
    ->charge();

charge() logs the customer in against Nass, derives a numeric orderId from the idempotency key, and calls Nass's POST /transaction. The returned PaymentResponse carries:

FieldPopulatedNotes
redirectUrlYesThe Nass-hosted checkout page. Send the customer here.
gatewayTransactionIdYesThe numeric orderId. Store it — webhooks and status() are keyed on it.
statusYesAlways PaymentStatus::Pending at this point.
qrCode, readableCode, deepLink, expiresAtNoNass Pay does not return these.

Send the customer to the hosted page:

php
return redirect()->away($response->redirectUrl);

The payment is not final yet. Nass calls your notifyUrl and the customer returns to your backRef — wait for the webhook (below) before marking the order paid.

Status check

NassGateway implements SupportsStatusCheck. You can poll Nass at any time with Payment::driver('nass')->status($gatewayTransactionId), which re-fetches the authoritative state. The parakit:transactions:sweep-pending command uses this to resolve stuck transactions.

Webhook / callback

Point NASS_CALLBACK_URL (the notifyUrl) at the package webhook route:

POST /payments/webhooks/nass

That route is registered by the package (name parakit.webhook) and handled by WebhookController. The payments/webhooks prefix comes from webhooks.route_prefix.

Nass callbacks carry no signature, so the callback body is never trusted on its own. handleWebhook() reads only the orderId from the request, then calls Nass's checkStatus endpoint server-to-server and uses that authoritative response. A missing orderId or any failure on the checkStatus call is treated as a verification failure and the controller answers 401.

Refunds

Nass Pay does not support refunds. NassGateway does not implement SupportsRefund, so there is no refund() method. Refund a Nass payment outside parakit, through Nass's own tooling.

Gotchas

  • Port in the base URL. base_url includes :9746. Keep the port when you set a production host.
  • Currency mapping. Nass expects an ISO 4217 numeric currency code, not a letter code. NassCurrencyMap translates the Currency enum: IQD368, USD840. Status responses are mapped back the same way; an unknown numeric code falls back to IQD.
  • Amount units. The charge sends the amount in major units as a string (Money::format). You still pass minor units to amount() — for IQD the minor-unit factor is 1, so dinars in equal dinars out.
  • Token TTL. The login token is cached for token_ttl seconds minus a 60s safety margin, with a 30s floor. On an HTTP 401 the client drops the token, re-logs in, and retries the call once.
  • Status codes. responseCode 00 is paid and -25 is cancelled. Codes -33, -39, -40, -47 mean "still processing" and map to Pending. Other negative codes are Failed. An unrecognised code logs parakit.nass.unknown_status and is treated as Pending rather than guessed.
  • Idempotency. The orderId is derived from the stable idempotency key (sha256 → first 60 bits as a numeric string), so a retried charge re-sends the same orderId and never double-creates a Nass transaction. Free-text caller keys (order:123) are folded through IdempotencyKey::forGateway first.

Released under the MIT License.