Your sandbox is active the moment you create an account — no approval needed.
Log in to your dashboard and copy the sk_test_... key from API Settings.
Use npm i @paymentgate/node or any other supported language SDK.
Use card number 4111 1111 1111 1111 to create a successful PaymentIntent.
Switch to "Test Mode" in the dashboard to view transactions, logs, and webhook attempts in real time.
Every Paymentgate account has two parallel key sets. The prefix makes it impossible to accidentally use the wrong key in the wrong environment.
sk_test_...No real money moves. Use freely in development, staging, and CI environments. Transactions never appear on any card statement.
sk_live_...Processes real charges. Treat as a password: never log, commit to git, or expose client-side. Rotate immediately if compromised.
pk_test_... / pk_live_...Safe to embed in front-end code. Only tokenises card data — cannot initiate charges or read sensitive data.
// .env.development PAYMENTGATE_SECRET_KEY=sk_test_Tj4nK8vLpR2xM6qW PAYMENTGATE_PUBLIC_KEY=pk_test_Hb2nL9pMqT5wX7vC // .env.production PAYMENTGATE_SECRET_KEY=sk_live_Kj7tN2mXpQ9wR4sL PAYMENTGATE_PUBLIC_KEY=pk_live_Qr3nV8bMwT6xN2pD // application code — environment-agnostic import Paymentgate from '@paymentgate/node'; const pg = new Paymentgate(process.env.PAYMENTGATE_SECRET_KEY); // The SDK detects test vs live automatically. // No code changes needed between environments.
Never hard-code keys. Always read from environment variables or a secrets manager like AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault.
Use any future expiry date (e.g. 12/30), any 3-digit CVC, and any 5-digit postal code. Card numbers below are for sandbox use only.
| Card Number | Brand | Outcome | Error Code | Use Case |
|---|---|---|---|---|
4111 1111 1111 1111 |
Visa | succeeded | — | Happy path charge |
4242 4242 4242 4242 |
Visa | succeeded | — | Generic success (no SCA) |
5555 5555 5555 4444 |
Mastercard | succeeded | — | Mastercard happy path |
4000 0000 0000 9995 |
Visa | declined | insufficient_funds | Show "insufficient funds" UI |
4000 0000 0000 0002 |
Visa | declined | card_declined | Generic card decline |
4000 0000 0000 0069 |
Visa | declined | expired_card | Expired card flow |
4000 0000 0000 0127 |
Visa | declined | incorrect_cvc | Wrong CVC handling |
4000 0000 0000 0119 |
Visa | processing_error | processing_error | Simulate processor timeout |
| Card Number | 3DS Behaviour | Final Outcome |
|---|---|---|
4000 0027 6000 3184 |
3DS required — authenticate | succeeded |
4000 0082 6000 3178 |
3DS required — fail challenge | declined (authentication_required) |
4000 0025 0000 3155 |
3DS2 frictionless — auto-passes | succeeded |
4000 0049 0000 0004 |
3DS optional — issuer exempts | succeeded (no challenge) |
| IBAN | Country | Outcome | Notes |
|---|---|---|---|
DE89 3704 0044 0532 0130 00 |
Germany (DE) | succeeded | Funds cleared in T+2 |
NL91 ABNA 0417 1643 00 |
Netherlands (NL) | succeeded | ABN AMRO test account |
FR76 3000 6000 0112 3456 7890 189 |
France (FR) | succeeded | BNP Paribas test |
AT61 1904 3002 3457 3201 |
Austria (AT) | declined | Simulate mandate rejection |
SE45 5000 0000 0583 9825 7466 |
Sweden (SE) | debit_not_authorized | Test dispute / chargeback |
Paymentgate delivers webhook events in test mode the same way it does in production. You can trigger any event type instantly from the dashboard or via the API.
Run pg listen --forward-to localhost:3000/webhooks to forward events to your local server without a public URL.
In the Dashboard → Webhooks → "Send test event", choose any event type and Paymentgate sends a realistic payload to your endpoint.
POST to /v1/webhooks/{id}/test with an event type string to fire a test event programmatically.
Signature verification works in test mode too. Always validate Paymentgate-Signature header — use your test webhook secret, not your live one.
import express from 'express'; import Paymentgate from '@paymentgate/node'; const app = express(); const pg = new Paymentgate(process.env.PAYMENTGATE_SECRET_KEY); // Use raw body for signature verification app.post('/webhooks', express.raw({ type: 'application/json' }), async (req, res) => { const sig = req.headers['paymentgate-signature']; let event; try { event = pg.webhooks.constructEvent( req.body, sig, process.env.WEBHOOK_SECRET // whsec_test_... ); } catch (err) { return res.status(400).send(`Webhook Error: ${err.message}`); } switch (event.type) { case 'payment_intent.succeeded': // fulfil order … break; case 'payment_intent.payment_failed': // notify customer … break; } res.json({ received: true }); } );
What behaves identically — and what intentionally differs — between environments.
| Feature | Sandbox | Production |
|---|---|---|
| API endpoints | Identical (api.paymentgate.com/v1/) |
Identical (api.paymentgate.com/v1/) |
| Real money movement | ||
| Webhook delivery | ||
| 3D Secure simulation | ||
| Fraud / ML scoring | Simulated (fixed outcomes) | Live ML model |
| Bank processing latency | Instant (simulated) | T+0 to T+2 actual |
| Payout settlement | No-op | Scheduled to bank account |
| Rate limits | 100 req/s per key | Per plan (see Pricing) |
| Data retention | 90 days | 7 years (GDPR compliant) |
Need a clean slate for a demo or to reproduce a bug from scratch? You can wipe all sandbox objects without affecting your live account.
Settings → Sandbox → "Reset sandbox data". Deletes all test transactions, customers, subscriptions, and webhook logs.
Call DELETE /v1/sandbox/reset with your test secret key. Returns 204 No Content on success.
Resets cannot be undone. Webhook secrets and API keys are preserved — only transaction data is deleted.
Run your payment integration tests on every pull request. Use your test secret key as a CI secret.
# GitHub Actions example name: Payment Integration Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest env: PAYMENTGATE_SECRET_KEY: ${{ secrets.PG_TEST_KEY }} WEBHOOK_SECRET: ${{ secrets.PG_WEBHOOK_SECRET }} steps: - uses: actions/checkout@v4 - run: npm ci - run: npm test
sk_test_ in CI secrets — never in code
DELETE /v1/sandbox/reset
status and last_payment_error.code — never on error messages (they can change)
Force specific outcomes by passing special metadata keys. Useful for automated tests that don't rely on specific card numbers.
metadata: { pg_test_outcome: "decline", pg_decline_code: "stolen_card" }
metadata: { pg_test_outcome: "delay", pg_delay_ms: 5000 }
metadata: { pg_test_outcome: "require_3ds", pg_3ds_result: "pass" }
Create a free account to get your test API keys. No credit card required. Full API parity from day one.