Going live
Moving to live is a configuration change on your side and an activation on ours. The code does not change — that is the point of the sandbox running the same binaries.
What actually changes
Section titled “What actually changes”| Sandbox | Live | |
|---|---|---|
| Base URL | https://sandbox.paysigna.com |
https://api.paysigna.com |
| Key | psg_test_… |
psg_live_… |
| Webhook endpoints | Registered in the test environment | Register again in live |
| Signing secrets | Test endpoint’s secret | A different secret per live endpoint |
Two things that catch people:
Webhook endpoints do not carry over. They belong to an environment. Register your production URL as a live endpoint and store its signing secret — it is not the same string as your test one.
Both the host and the key have to change together. A psg_test_… key against
api.paysigna.com is a 403 with code environment_mismatch, and so is the
reverse. The environment is baked into the key string so you can catch this before
you deploy rather than after.
Before a live key will work
Section titled “Before a live key will work”These are enforced, and each has its own error code so you can tell which one you are hitting:
| Must be true | Error if not |
|---|---|
| The account is activated | merchant_not_live |
| KYC is complete — ID, settlement account, a description of what you sell | kyc_required |
| A settlement destination is on file | settlement_destination_missing |
| API access is enabled for the account | api_integration_not_enabled |
| The channel you are using is enabled | capability_disabled |
| Pricing is configured for your merchant and channel | unpriced_combination |
The last one is ours, not yours. If you see unpriced_combination on a live
request, tell us — it means no fee is configured for that combination and nothing
you can do in the portal will fix it.
All of the others are resolved in the merchant portal at app.paysigna.com, or by asking us.
A checklist worth actually running
Section titled “A checklist worth actually running”Your integration is ready when all of these are true in the sandbox:
- Your records update from the webhook, not from the create response.
- A retried create with the same
Idempotency-Keyproduces one payment, not two. - Your webhook handler reads the raw body, accepts any
v1=element, compares in constant time, and rejects timestamps older than five minutes. - It deduplicates on event
idand returns inside its timeout. - You record the highest
sequenceprocessed, and know how to backfill from it. - You reconcile against
merchant_amount, notamount. -
awaiting_actionandpendingare handled as normal outcomes, not failures. -
manual_review_pendingdoes not tell the customer the payment failed. -
partner_timeoutreads the transaction before deciding anything. - You log
X-Request-Idalongside your own record of every call. - You alert on the
PaySigna-Key-Grace-Expiresheader.
Hardening the live key
Section titled “Hardening the live key”Scope it down. Grant the narrowest set of scopes the integration actually uses. A key that can only create and read collections cannot be used to create a payout if it leaks. See Authentication.
Allowlist your egress IPs. If you call from fixed addresses, turn this on. A leaked key then becomes unusable from anywhere else.
Separate keys per system. One key per service or per environment, not one key shared everywhere. Rotation is then a contained operation rather than a coordinated outage.
Rotate on a schedule, and watch the grace header. After a rotation, every
response still authenticated by the old key carries
PaySigna-Key-Grace-Expires. If that header is still appearing in your logs, some
server is still holding the old credential — and if you do not notice, you will
find out when all of them fail at the same instant.
Why you cannot test the live API from this page
Section titled “Why you cannot test the live API from this page”The request console on the API reference only offers the sandbox. The live host is not in its server list — not hidden in the interface, but absent from the OpenAPI document this site loads, so there is nothing to select.
The reasoning is the same reasoning that gives publishable keys a purpose: a browser calling a secret-key endpoint means the secret key is in the browser, which is the thing publishable keys exist to prevent. A request console on a public documentation site is exactly that browser, and making it work against live would mean this page could hold a live secret key.
So the console targets sandbox.paysigna.com, where keys are test keys and no
real money can move, and live traffic comes from your servers. If you want to
check a live call by hand, use curl from a machine you control.
When something is wrong in production
Section titled “When something is wrong in production”- Get the
X-Request-Idfrom the response, orrequest_idfrom the error body. - Check status.paysigna.com for a partner outage.
- Read the transaction — the response is never the only record, and a timeout is not evidence that nothing happened.
- Mail [email protected] with the request id and
the PaySigna
reference. Those two strings are the difference between a five-minute answer and a long conversation.
For anything that looks like a security issue, including a leaked key, write to [email protected] and rotate the key first.

