Skip to main content
Sniko supports three payment gateways: Stripe, Razorpay, and Paystack. You can enable one or more providers simultaneously. The platform selects the best provider per user based on their location or your configured default. All providers share the same subscription lifecycle model: created → active → cancelled → expired.

Environment overview

Sniko supports a sandbox and live payment environment, controlled by:
.env
PAYMENT_ENVIRONMENT=sandbox   # or: live
When set to sandbox, Sniko uses test keys for Stripe and test mode flags for Razorpay and Paystack. The Stripe configuration automatically selects the correct key set based on this value.

Stripe

Credentials

Stripe uses separate key sets for test and live environments. Configure all six values — Sniko selects the active set based on PAYMENT_ENVIRONMENT:
.env
# Test environment
STRIPE_TEST_PUBLISHABLE_KEY=pk_test_...
STRIPE_TEST_SECRET_KEY=sk_test_...
STRIPE_TEST_WEBHOOK_SECRET=whsec_...

# Live environment
STRIPE_LIVE_PUBLISHABLE_KEY=pk_live_...
STRIPE_LIVE_SECRET_KEY=sk_live_...
STRIPE_LIVE_WEBHOOK_SECRET=whsec_...
The legacy single-key variables STRIPE_KEY, STRIPE_SECRET, and STRIPE_WEBHOOK_SECRET (from config/services.php) are also read and used by the refund and customer management services. Set them to match your active environment’s keys.
Key format requirements:
  • Publishable key must start with pk_
  • Secret key must start with sk_
  • Webhook secret must start with whsec_
You can validate your Stripe configuration at any time:
GET /api/stripe/validate

Webhook endpoint

Register the following endpoint in your Stripe Dashboard under Developers → Webhooks → Add endpoint:
POST {APP_URL}/webhooks/stripe
Sniko handles the following Stripe webhook events:
EventEffect
customer.subscription.createdCreates or updates local subscription record
customer.subscription.updatedSyncs plan, status, and period dates
customer.subscription.deletedMarks subscription as cancelled
invoice.payment_succeededMarks subscription as active
invoice.payment_failedMarks subscription as past due
customer.createdStores Stripe customer ID on the user
customer.updatedSyncs customer metadata
payment_method.attachedRecords the new payment method
After adding the endpoint in Stripe, copy the Signing Secret and set it as STRIPE_TEST_WEBHOOK_SECRET or STRIPE_LIVE_WEBHOOK_SECRET (matching your environment).
Stripe webhook requests must not go through CSRF verification. Sniko excludes /webhooks/stripe from CSRF middleware automatically. Do not add this route behind any authentication middleware.

Currency

The default billing currency is USD. Override it with:
.env
STRIPE_CURRENCY=usd

Razorpay

Razorpay is recommended for customers in India (INR billing). Sniko automatically routes Indian users to Razorpay when it is the active provider.

Credentials

.env
RAZORPAY_API_KEY=rzp_test_...        # or rzp_live_...
RAZORPAY_SECRET_KEY=your_secret_key
RAZORPAY_WEBHOOK_SECRET=your_webhook_secret
RAZORPAY_TEST_MODE=true              # set to false for live
RAZORPAY_FEE_PERCENTAGE=2.0          # optional processing fee percentage
RAZORPAY_FEE_FIXED=0.0               # optional fixed fee in INR
Credentials can also be stored in the database via Admin → Payments → Providers and will be loaded from there if env vars are absent.

Webhook endpoints

Razorpay sends event notifications to two routes in Sniko:
POST {APP_URL}/webhooks/razorpay
POST {APP_URL}/razorpay/webhook
Register {APP_URL}/webhooks/razorpay in your Razorpay Dashboard under Settings → Webhooks. Add your RAZORPAY_WEBHOOK_SECRET as the webhook secret.

Currency conversion

Razorpay charges in INR. Sniko uses a live exchange rate service to convert USD plan prices to INR at checkout. A fallback rate of ₹83 per USD is used if the exchange rate API is unavailable.

Paystack

Paystack is recommended for customers in Nigeria (NGN), Ghana, South Africa, and Kenya. Sniko automatically routes users from these countries to Paystack when it is an active provider.

Credentials

.env
PAYSTACK_SECRET_KEY=sk_test_...      # or sk_live_...
PAYSTACK_PUBLIC_KEY=pk_test_...      # or pk_live_...
PAYSTACK_WEBHOOK_SECRET=your_webhook_secret
PAYSTACK_MERCHANT_CURRENCY=NGN
PAYSTACK_TEST_MODE=true              # set to false for live
Like Razorpay, Paystack credentials can be managed in the database through Admin → Payments → Providers.

Webhook endpoint

POST {APP_URL}/webhooks/paystack
POST {APP_URL}/paystack/webhook
Register {APP_URL}/webhooks/paystack in your Paystack Dashboard under Settings → API Keys & Webhooks.

Enabling and disabling providers

All three providers are managed from the admin panel:
1

Open the Payments admin

Navigate to Admin → Payments → Providers (/admin/payments/providers).
2

Add or edit a provider

Click Add Provider or select an existing one. Enter the provider name, type (stripe, razorpay, or paystack), and credentials. Credentials entered here are stored in the database and take precedence over matching env vars.
3

Set a default provider

Mark one provider as the default. This provider is used when no location-based routing rule applies. Only one provider can be the default at a time.
4

Toggle a provider on or off

Use the Toggle action to enable or disable a provider without deleting its configuration. Disabled providers are not offered to users at checkout.

Plan mapping

Each pricing plan must be linked to a product ID in each active payment provider. This mapping tells Sniko which provider-side product to use when creating a subscription. Navigate to Admin → Payments → Plan Mapping (/admin/payments/plan-mapping):
  • Stripe: Sniko automatically creates Stripe Products and Prices when you create or update a plan. The stripe_product_id, stripe_monthly_price_id, and stripe_yearly_price_id are stored on the PricingPlan model.
  • Razorpay: Enter the Razorpay Plan ID for monthly and yearly billing cycles.
  • Paystack: Enter the Paystack Plan Code for monthly and yearly billing cycles.
For Stripe, you can re-sync all plans to Stripe at any time by calling StripeService::syncAllPlansToStripe() from Tinker or a scheduled command. This is useful after changing plan prices or feature lists.

Subscription lifecycle

All providers follow the same subscription state machine inside Sniko:
StatusDescription
incompletePayment initiated but not yet confirmed (Stripe only)
activeSubscription is paid and valid
trialingIn a free trial period
past_dueLast payment failed; access may be restricted
canceledSubscription cancelled; access ends at period end
expiredSubscription has ended
Subscription states are updated in real time via webhooks. You can also force a sync from the provider:
POST /subscriptions/{subscription}/sync-usage

Cancellation

Subscriptions can be cancelled immediately or at the end of the current billing period:
  • Cancel at period end: the subscription remains active but cancel_at_period_end is set to true. Access continues until the period ends.
  • Immediate cancellation: the subscription status is set to canceled instantly.
Free plan subscriptions (no external_id) are cancelled locally without any provider API call.

Refunds

Refunds are processed through the subscription’s original payment provider. Navigate to Admin → Payments → Subscriptions, select a subscription, and click Refund. You can also issue a refund via the API:
POST /subscriptions/{subscription}/refund
The refund is forwarded to the active gateway for that subscription. Partial refund amounts can be specified; if no amount is given, a full refund is issued.
Stripe refunds are processed immediately through the Stripe API. The refund ID is logged and stored in the subscription metadata. Stripe returns the refunded amount and status in the response.
Razorpay refunds are initiated via the Razorpay API against the original payment ID stored in the subscription’s external_id. Processing time is typically 5–7 business days.
Paystack refunds are submitted to the Paystack refund endpoint. The transaction reference from the original payment is required and is stored in subscription metadata at checkout.

Build docs developers (and LLMs) love