Skip to content

Environments

Pdirect runs three environments. They are configuration-distinct, not URL-prefixed — the same paths exist at every base URL.

EnvironmentBase URLPurpose
Sandboxhttps://app.api.gtwy.pdirect.comSelf-serve test credentials. Money is fake. The default for new integrations.
Staginghttps://staging.app.api.gtwy.pdirect.comPre-production. Same processor connections as production but with test credentials. Used for release-candidate verification.
Productionhttps://app.api.gtwy.pdirect.comLive money. Real customers. Real settlement.

Every payment endpoint is mounted under /api/v1/. Health probes (/health, /api/v1/payments/health) are not versioned and behave the same in every environment.

Use the base URL of the target environment. There is no global “environment” toggle — Authorization: Bearer <merchant_secret> and the choice of base URL together determine which environment you hit. A sandbox merchant_secret will not authenticate against the production base URL.

Terminal window
curl https://app.api.gtwy.pdirect.com/api/v1/payments/health
# {"status":"healthy","service":"pdirect-payment-gateway","timestamp":"...","version":"1.0.0"}

Pick the environment once at app startup; the SDK derives the base URL internally and does not allow it to be overridden (intentional PCI-scope reduction).

import 'package:flutter/material.dart';
import 'package:pdirect_pay/pdirect_pay.dart';
void main() {
PdirectPay.init(const PdirectPayConfig(
environment: PdirectPayEnvironment.production, // or .staging / .sandbox
defaultLocale: 'fr',
));
runApp(const MyApp());
}

PdirectPayEnvironment.sandbox resolves to app.api.gtwy.pdirect.com, .staging to staging.app.api.gtwy.pdirect.com, .production to app.api.gtwy.pdirect.com.

The Angular SDK uses an isProduction boolean. There is no separate “staging” enum value — point at staging via customApiUrl.

import { PdirectPayConfig } from "@mms/pdirect-pay";
const configs: PdirectPayConfig = {
token: "your-app-key", // Auth-v2 (legacy, see /sdks/overview)
isProduction: false, // false → sandbox, true → production
acceptLanguage: "en",
};

Override the base URL when you need staging or a private deployment:

const configs: PdirectPayConfig = {
token: "your-app-key",
isProduction: false,
customApiUrl: "https://staging.app.api.gtwy.pdirect.com",
acceptLanguage: "en",
};

Each environment issues its own merchant_secret (and, when signing ships, its own webhook_secret). They are not interchangeable.

Terminal window
# Wrong — sandbox secret against production base URL
curl https://app.api.gtwy.pdirect.com/api/v1/internal/sessions/create \
-H "Authorization: Bearer mch_sandbox_xxx:sk_test_yyy" \
...
# → 401 with error_code: "1001" (INVALID_APP_KEY)

When rotating, plan for both the old and new secret to be valid during the window — the gateway supports overlapping active keys per merchant per environment.

  • No real settlement. Mobile-money “approvals” return immediately without actually moving money. Card flows still walk the full Mastercard hosted-session and 3DS journey but resolve against test card numbers.
  • Test card numbers. Use Mastercard’s published test PANs (e.g. 5123 4500 0000 0008 with any future expiry and any CVV). 3DS challenges resolve in the sandbox-issued challenge form.
  • Test phone numbers. Mobile-money flows accept +243998857000 and a few neighbouring numbers as guaranteed-success test MSISDNs. Other numbers can fail with realistic error codes for testing purposes.
  • Webhooks fire normally. Sandbox notify_url callbacks are real HTTP POSTs from the gateway. Use a service like webhook.site to inspect them during development.
  • Rate limits are the same. 30/min per session, 5/5min on OTP. Don’t tune your test harness on sandbox-specific limits.