Skip to content

Artisan commands

Parakit ships seven parakit:* Artisan commands. They cover one-time setup, runtime diagnostics, and the recurring operations that keep payment data consistent. Run any of them with php artisan:

bash
php artisan parakit:install
php artisan parakit:doctor --gateway=fib

Quick reference

CommandGroupWhat it does
parakit:installSetupPublishes config and migrations, then runs migrate.
parakit:doctorDiagnosticsChecks gateway config and FIB token connectivity.
parakit:transactions:test-chargeDiagnosticsRuns a sandbox charge end to end.
parakit:webhooks:simulateDiagnosticsPosts a signed test webhook to your local app.
parakit:receipts:previewDiagnosticsRenders sample receipts to disk for design review.
parakit:transactions:sweep-pendingOperationsPolls pending transactions to recover lost webhooks.
parakit:logs:pruneOperationsDeletes payment_logs rows past the retention window.

All commands return 0 on success. Failure codes are noted per command below.

Setup

parakit:install

Publishes the package config and migrations, then migrates the database. Run this once after installing the Composer package.

parakit:install {--force}
OptionDefaultDescription
--forceoffOverwrite an existing published config/parakit.php.

What it does, in order:

  1. Publishes config/parakit.php (tag parakit-config). Without --force, an existing config file is left untouched so re-running the command does not clobber operator edits.
  2. Publishes the migrations (tag parakit-migrations). These are always force-published — migrations are timestamped and additive, so a republish is safe.
  3. Runs migrate. In the production environment it passes --force so a non-interactive deploy does not hang on the confirmation prompt.

Receipt templates are not published automatically. To customise them, run the extra step the command prints:

bash
php artisan vendor:publish --tag=parakit-views
bash
# First install
php artisan parakit:install

# Re-publish config after a package update, overwriting local edits
php artisan parakit:install --force

Exit code: always 0.

TIP

See Installation and Configuration for the full setup walkthrough and the credentials each gateway needs.

Diagnostics

parakit:doctor

Verifies that each configured gateway has the config keys it needs, and — for FIB — that the credentials can actually fetch a token.

parakit:doctor {--gateway=}
OptionDefaultDescription
--gateway=all gatewaysLimit the check to a single gateway key.

For each gateway it checks the required config keys:

DriverRequired keys
fibbase_url, client_id, client_secret, callback_url
zaincashbase_url, client_id, client_secret, api_key
nassbase_url, username, password, callback_url
nasswalletbase_url, portal_url, basic_token, username, password, transaction_pin, callback_url
fastpaybase_url, store_id, store_password, callback_url
qicardbase_url, username, password, terminal_id
any otherNo built-in check — prints a warning to verify manually.

When FIB credentials are present, the command clears the cached FIB token (parakit:fib:token) and forces a fresh fetch. A cached token from a rotated secret would otherwise let the check pass while live charges return 401.

bash
# Check every configured gateway
php artisan parakit:doctor

# Check only FIB
php artisan parakit:doctor --gateway=fib
Exit codeMeaning
0All checks passed.
1A gateway is missing config, failed the FIB token fetch, or no gateways are configured.

WARNING

Drivers registered through Payment::extend() have no built-in config check. The doctor reports a warning for them rather than a false OK.

parakit:transactions:test-charge

Runs a real sandbox charge against a gateway to prove the integration works end to end. Use it after configuring credentials.

parakit:transactions:test-charge {gateway} {--amount=1000} {--currency=IQD}
ArgumentRequiredDescription
gatewayyesGateway key to charge (fib, zaincash, nass, nasswallet, fastpay, qicard).
OptionDefaultDescription
--amount=1000Charge amount in minor units (whole dinars for IQD, cents for USD).
--currency=IQDCurrency code — must be a valid Currency enum value (IQD, USD).

The command builds a PaymentRequest with a random test_* reference and charges the gateway. On success it prints the gateway transaction id and any redirect URL, readable code, or deep link the response carries.

bash
php artisan parakit:transactions:test-charge fib --amount=5000 --currency=IQD
Exit codeMeaning
0Charge succeeded.
2Unknown currency passed to --currency.

WARNING

The random reference suffix is sandbox-only and is not collision-safe at production volumes. Point this command at sandbox credentials.

parakit:webhooks:simulate

Posts a test webhook to your local app, so you can exercise your webhook handling without waiting on the real gateway.

parakit:webhooks:simulate {gateway} {--status=paid} {--reference=} {--transaction-id=} {--sign-with=}
ArgumentRequiredDescription
gatewayyesGateway key — fib, zaincash, nass, nasswallet, fastpay, or qicard.
OptionDefaultDescription
--status=paidPayment status to report. paid maps to each gateway's success status.
--reference=emptyYour order reference to put in the payload.
--transaction-id=emptyGateway transaction id to put in the payload.
--sign-with=emptyPath to a PEM-encoded RSA private key. QiCard only — signs the canonical payload string and adds the X-Signature header so your verification path exercises end to end. Without this flag the qicard simulator posts an unsigned body, exercising the fallback (status re-check) path instead.

The webhook is posted to {route_prefix}/{gateway} on your app URL — except NassWallet, which is posted to {route_prefix}/nasswallet/callback. Each gateway gets a payload shaped like its real callback:

GatewayPayload
zaincashHS256 JWT signed with the configured api_key.
fibFlat id / status form body.
nassFlat orderId / responseCode form body.
nasswalletJSON { "data": { ... } } envelope keyed by InitTransactionId.
fastpayFlat order_id / status form body.

The command prints the HTTP status and response body.

TIP

NassPay, NassWallet, and FastPay re-fetch the authoritative status from the gateway when a callback arrives. A simulated webhook still exercises your route and controller, but that server-side re-fetch will hit the real gateway — so the transition only applies if the gateway recognises the transaction id.

bash
php artisan parakit:webhooks:simulate fib \
  --status=paid \
  --reference=ORD-2048 \
  --transaction-id=pid_5f3a9c2e
Exit codeMeaning
0The webhook endpoint returned a 2xx response.
1The endpoint returned a non-2xx response.

See Handling webhooks for how the endpoint verifies and processes these requests.

parakit:receipts:preview

Renders sample receipts to disk so you can review template designs without wiring up a real payment.

parakit:receipts:preview {--template=modern} {--type=payment} {--locale=en} {--format=html} {--output=} {--all}
OptionDefaultDescription
--template=modernTemplate to render: modern, classic, or minimal.
--type=paymentReceipt type: payment or refund.
--locale=enRender locale: en, ar, or ckb.
--format=htmlOutput format: html or pdf. HTML is fastest for design iteration.
--output=storage/parakit-receiptsDirectory to write files into. Created if missing.
--alloffRender every template × type × locale combination.

Each file is written as {template}-{type}-{locale}.{format}. The command uses a built-in sample transaction (a paid ORD-2048 for payment, partially refunded for refund), so no database row is required.

bash
# Preview one combination as HTML
php artisan parakit:receipts:preview --template=classic --type=refund --locale=ar

# Render every combination as PDF
php artisan parakit:receipts:preview --all --format=pdf
Exit codeMeaning
0All receipts rendered.
1Invalid --format, unknown --template/--type, or the output directory could not be created.

See Receipts for the receipt API.

Operations

These commands are meant to run on a schedule. Register them in your application's scheduler — for example in routes/console.php:

php
use Illuminate\Support\Facades\Schedule;

Schedule::command('parakit:transactions:sweep-pending')->everyFiveMinutes();
Schedule::command('parakit:logs:prune')->daily();

parakit:transactions:sweep-pending

Polls the gateway for the status of transactions still in Pending or Processing, then reconciles their local status. This recovers transactions whose webhook was lost or never delivered.

parakit:transactions:sweep-pending {--gateway=} {--older-than=}
OptionDefaultDescription
--gateway=all gatewaysLimit the sweep to one gateway key.
--older-than=parakit.sweeper.older_than_minutes (5)Only sweep rows untouched for at least this many minutes.

It selects payment_transactions that are Pending or Processing, were last updated at least --older-than minutes ago, were created within parakit.sweeper.max_age_hours (default 24), and have a gateway_transaction_id. For each row it calls the gateway's status check and applies any status change inside a row-locked DB transaction, so it never races with an incoming webhook.

When a status actually changes, it dispatches the matching event:

New statusEvent dispatched
PaidPaymentSucceeded
FailedPaymentFailed
Cancelled, ExpiredPaymentCancelled

Gateways that do not implement SupportsStatusCheck are skipped.

bash
# Sweep everything older than the configured window
php artisan parakit:transactions:sweep-pending

# Sweep only FIB rows untouched for 15+ minutes
php artisan parakit:transactions:sweep-pending --gateway=fib --older-than=15

Exit code: always 0. The command prints how many transactions it updated.

See Reliability for how the sweeper fits into parakit's recovery model.

parakit:logs:prune

Deletes old rows from the payment_logs table to keep it from growing without bound.

parakit:logs:prune {--days=}
OptionDefaultDescription
--days=parakit.logging.retention_days (90)Delete payment_logs rows older than this many days.
bash
# Use the configured retention window
php artisan parakit:logs:prune

# Keep only the last 30 days
php artisan parakit:logs:prune --days=30

Exit code: always 0. The command prints how many rows it deleted.

Released under the MIT License.