Go-Live Checklist

Validate business, domain, NRS, billing, security, retry, and operational readiness before sending live invoices.

Use test state to prove the complete customer and failure journey, then treat live as a separate controlled launch. A successful NRS sign alone is not enough: the integration also needs durable mappings, billing recovery, delivery handling, security controls, and an operator runbook.

Release path

  1. Prove test

    Exercise the approved mode, NRS validation/signing, billing failures, retries, transmission, and inbound processing.

  2. Drain

    Have Duplo place the domain in draining and clear all non-terminal billing, Stored, and transmission work.

  3. Change state

    Complete the controlled Duplo Dashboard state switch, sign in again, and create the target-state credential.

  4. Reapprove

    Configure the new credential and wait until the domain is approved in the target state and mode.

  5. Re-onboard and ramp

    Onboard represented businesses only after approval, then start with monitored traffic.

1. Business readiness

2. Credential and domain readiness

Run a non-billable host check:

curl https://acme.invoice.tryduplo.com/health
Host health response
{ "status": "ok" }

Then run an authenticated, unbilled NRS self-health check:

curl \
  --url https://acme.invoice.tryduplo.com/api/v1/invoice/transmit/self-health-check \
  --header 'x-api-key: pk_live_replace_with_your_key'

Do not use either health response as proof that a wallet is funded or a represented business is correctly mapped.

Also configure deployment probes deliberately: /health/live is process liveness, while /health/ready covers local initialization and the Redis safety dependency. A shared Spend or NRS outage does not deliberately make every Gateway pod unready. Duplo operators use the protected, cached /health/dependencies view for dependency, circuit, capacity, processor-heartbeat, and recovery state; customers must not treat that route as a live NRS probe.

3. Represented-business readiness

For every issuer, maintain a durable mapping such as:

Represented-business mapping to retain
{
  "yourCustomerId": "erp-customer-1042",
  "gatewaySubBusinessId": "nrs-business-demo",
  "firsBusinessId": "nrs-business-demo",
  "nrsIdentity": {
    "entityId": "entity-demo",
    "entityReference": "entity-reference-demo",
    "nrsBusinessId": "nrs-business-demo",
    "businessName": "Acme Retail Limited",
    "tin": "12345678-0001",
    "irnTemplate": "{{invoice_id}}-2A3A045D-{{YYYYMMDD}}"
  },
  "businessState": "live",
  "cryptoVersion": 0
}

cryptoVersion: 0 is a valid production state: it means no QR material is stored. Gateway stores supplied values opaquely and discovers an unusable public key only when QR generation is attempted. QR generation is best-effort and must not be used as proof that onboarding, signing, or transmission succeeded.

4. Invoice-data readiness

Validate representative invoice fixtures before any sign test:

  • Smallest and largest expected invoices.
  • Multiple line items and multiple tax subtotals.
  • Commercial invoice plus every note/type your product supports.
  • Receiver connected and receiver unavailable.
  • Invalid TIN, expired resource code, bad total, duplicate IRN, and malformed body.
  • Additive NRS fields, changed types, malformed success JSON, unexpected 202, empty 204, provider 401/403, 429, redirect, timeout, and oversized response fixtures.
  • Payload near your configured application limit; Gateway's default buffered ceiling is 10 MiB.

5. Mode-specific readiness

Pass-through

Stored

6. Billing and failure drills

Prove these behaviors in an authorized test environment:

DrillExpected system behavior
Insufficient wallet balanceNRS is not called; invoice stays recoverable; operator sees 402 GW_BILLING_WALLET_DECLINED guidance
Invalid NRS documentValidation/sign rejection is recorded; no blind retry loop starts
Pass-through successOne charge and one durable sign result are correlated to IRN, idempotency identity, and request ID
Duplicate Pass-through attempt409 enters original-result recovery; a random key is not generated automatically
Simulated GW_SIGN_OUTCOME_UNCONFIRMEDAutomation freezes that IRN and creates a reconciliation case with requestId
Stored intake response lostExact request is resent with the same command key and resolves to one invoice
Stored worker remains pendingPoller backs off and alerts after its own service-level deadline without resubmitting
Transmission timeoutSystem reads current state and retries delivery only; it never signs again
Rate limitCaller uses bounded jittered backoff and caps concurrency; honor Retry-After if a route supplies it
Slow or incomplete request bodyCaller handles GW_REQUEST_BODY_TIMEOUT, sends the complete body promptly, and retains the same mutation identity
Gateway capacity fullCaller handles GW_GATEWAY_CAPACITY_EXCEEDED, honors Retry-After, and does not fan out to another host or key
Runtime routing loopGateway returns 508 GW_ROUTING_LOOP_DETECTED; automation stops until the upstream route is corrected

Finance and engineering should be able to reconcile, for a chosen period:

Reconciliation chain
Your sign commands
↔ Gateway request ID/idempotency/IRN
↔ NRS result or reconciliation state
↔ Duplo signing fee movement/reversal

7. Webhook readiness

Inbound receipt is a separately approved launch scope

Do not use this checklist as proof that inbound NRS callbacks are enabled. Before you include inbound receipt in test or live scope, obtain Duplo confirmation that the environment has trusted-edge path proof, independent NRS sender authentication or an authoritative NRS source restriction, WAF/rate controls, and a proven callback timing and crash-recovery decision. The current handler completes NRS download/decrypt processing before acknowledging the callback and records caught processing failures without asking NRS to retry them. If those controls and a durable recovery path have not been certified, Duplo must leave the callback unregistered and your release must explicitly exclude inbound receipt.

See Verifying events for how an authenticated invoice read establishes invoice truth while the webhook request itself remains unsigned.

8. Security review

9. Production cutover

  1. Stop test invoice producers and reconcile every in-flight sign, non-terminal billing attempt, Stored invoice, and unresolved transmission.
  2. Coordinate with Duplo to place the approved domain in draining, prepare it for target-state reapproval, and complete the Duplo Dashboard state transition. Expect the prior key/refresh context, represented-business access, and domain approval to stop being usable.
  3. Sign in again and generate a new live API key.
  4. Configure the live webhook and intended caller IPs on that credential; if you rely on IP restriction, confirm that Duplo has enabled enforcement in live.
  5. Wait until the domain reports approved in live with the expected mode/version.
  6. Complete live represented-business onboarding and save the new state-bound mappings.
  7. Run health, NRS resource, recipient lookup, and validation checks before the first billed sign.
  8. Send one controlled invoice, persist its complete safe audit trail, transmit it, and reconcile the sign fee.
  9. Ramp volume in stages while watching billing, NRS latency/error rate, Stored queue age where applicable, and webhook delivery.

Do not bypass reapproval

A state or mode mismatch returns 409 by design. Do not change the hostname, forge state/mode fields, reuse a revoked key, or call NRS directly to work around it. Finish the controlled domain workflow and preserve in-flight reconciliation.

Operator runbook

Document these decisions before launch:

SignalOwnerImmediate actionEscalation data
401 surgeSecurity/integrationVerify secret deployment and key status; stop rotation loopsHost, state, timestamps, key prefix/last four only
409 state or mode driftPlatform ownerPause intake and read current domain configurationDomain status, mode/version, request ID
GW_BILLING_WALLET_DECLINEDFinance + operationsPause billed intake; check wallet/account readinessRequest ID, IRN, child ID, UTC time, sanitized error
GW_SIGN_OUTCOME_UNCONFIRMEDReconciliation ownerFreeze the IRN and preserve evidence; do not re-signRequest ID, operation ID when present, idempotency key, NRS lookup
GW_TRANSMIT_ATTEMPT_ALREADY_PROCESSEDReconciliation ownerUse the returned operation ID; do not bypass the existing claimRequest ID, operation ID, IRN, idempotency key
GW_TRANSMIT_OUTCOME_UNCONFIRMEDReconciliation ownerFreeze transmission and reconcile its durable claim; do not resendRequest ID, operation ID, IRN, idempotency key, NRS lookup
GW_GATEWAY_CAPACITY_EXCEEDEDGateway operatorCheck noisy-domain, process, Redis, socket, and dependency saturation; retain caller keysRequest IDs, route, domain hash, capacity snapshot
GW_ROUTING_LOOP_DETECTEDPlatform/networkStop retries and correct DNS, proxy, origin, or service discoveryRequest ID, environment, configured target, route
Stored pending beyond SLOOperationsKeep read-only polling bounded and open an investigationInvoice ID, IRN, child ID, timestamps
Webhook outageApplication ownerRestore 2xx receiver, verify reachability, reconcile via invoice APIDelivery/invoice IDs and outage window
NRS resource rejectionTax/integrationRefresh current catalog and review payload mappingNRS status/body, resource version/time

Use the Gateway operations runbook for dependency, health, circuit, Slack, and recovery procedures, and the billing support packet for Duplo escalation. Never include full credentials or private cryptographic material.

How is this guide?

On this page