Authentication

Every Scan & Pay API request authenticates with a single header carrying your API Secret. There is no OAuth dance, no signed-request scheme, no nonces — keep the secret server-side and send it on every call.

The X-Scanpay-Key header

Set the header on every request to api.scanandpay.com.au except /ping. Requests without it return 401 Unauthenticated.

curlbash
curl https://api.scanandpay.com.au/createPaymentSession \
  -X POST \
  -H "X-Scanpay-Key: $SCANANDPAY_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "xxxxxxxxxxxxxxxxxxxx",
    "platformOrderId": "order_456",
    "amount": 19.90,
    "payId": "merchant@example.com.au",
    "merchantName": "Acme Coffee"
  }'

The same header is used by both official SDKs:

PHP — scanandpay/phpphp
use ScanAndPay\ScanAndPay;

$client = new ScanAndPay(
    merchantId: 'xxxxxxxxxxxxxxxxxxxx',
    apiSecret: getenv('SCANANDPAY_API_SECRET'),
);
TypeScript — @scanandpay/nodets
import { ScanAndPay } from '@scanandpay/node';

const sp = new ScanAndPay({
  merchantId: 'xxxxxxxxxxxxxxxxxxxx',
  apiSecret: process.env.SCANANDPAY_API_SECRET!,
});

Where to find your credentials

  1. 1Sign in to merchant.scanandpay.com.au.
  2. 2Open Settings → Integrations.
  3. 3Copy Merchant ID, API Base URL, API Secret, and Webhook Secret into your environment variables.
.envbash
SCANANDPAY_MERCHANT_ID=xxxxxxxxxxxxxxxxxxxx
SCANANDPAY_API_SECRET=sp_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SCANANDPAY_WEBHOOK_SECRET=sp_wh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SCANANDPAY_API_BASE_URL=https://api.scanandpay.com.au

Rotation

Press Regenerate API Credentials in the dashboard only when you believe a secret is compromised. Rotation is immediate and total: the old API Secret and Webhook Secret are revoked the moment the new pair is issued. Every connected system fails closed until you paste in the new values.

Plan rotations during low traffic. There is no grace period and no overlap — both production and staging consume the same single credential set today.

Test vs live

No separate test environment yet. Every call hits the production API and creates real payment sessions. To test an integration without taking real money: create a session for a low amount (e.g. 0.01) and simply do not pay it — the session expires after 5 minutes. A sandboxed test mode is on the roadmap.

Authentication errors

StatuserrorCause
401Missing X-Scanpay-Key headerHeader not set, or empty.
401Invalid API keyHeader set but does not match an active key. Check for stale rotation.
403SUBSCRIPTION_REQUIREDMerchant account has no active subscription. The merchant must update billing in the dashboard.

Next