Getting Started — Transxact Developer Quickstart
Welcome to Transxact. This guide walks you through creating your first payment integration in test mode, covering all three payment rails (M-PAiSA, MyCash, cards). The core object you will work with is the payment intent; follow the steps in order, each building on the previous one.
1. Create a Transxact Account
If you don't already have an account:
- Sign up at
https://merchant.transxact.io(or contact your Transxact onboarding partner). - Complete the onboarding track that applies to you:
- Business — registered legal entity. Requires full CDD/EDD (FTR Act s.4).
- Sole trader — natural person selling as themselves. Reduced EDD document set.
- After signup, your account is assigned a risk tier (Low, Standard, High) based on continuous transaction monitoring.
- Your account tier determines:
- Which rails are enabled for you (M-PAiSA, MyCash, cards).
- Due diligence depth (simplified CDD, standard CDD, or EDD).
- Transaction-monitoring thresholds and reserve defaults.
Why this matters: The three rails have different integration patterns. M-PAiSA and cards use redirect-based flows; MyCash uses server-to-server OTP collection. Your risk tier and enabled rails will dictate which flows you need to implement.
2. Set Up Your Development Environment
Install the transxact CLI
npm install -g transxact-cli
# or, using the SDK quickstart:
transxact sandbox create --help
Authenticate
transxact keys:create --mode test
This creates a test secret key (sk_test_...) and publishable key (pk_test_...) scoped to test mode. Keys are automatically scoped to your account's enabled rails.
Recommended: Test Mode Walkthrough
Transxact's test mode simulates every rail inside the aggregator — no real money, no external calls. Outcomes are forced by magic values (detailed in step 4).
Stripe-pattern adaptation: Like Stripe's sandbox, Transxact test mode uses magic values instead of real rail calls. Unlike Stripe, Transxact simulates three rails with different patterns (redirect, OTP, hybrid).
3. Create Your First Payment Intent
Using the transxact CLI (recommended for test mode)
transxact payments:create \
--amount 2500 \
--reference "order-1234" \
--return-url "https://you.example.com/thanks"
Using the API directly
POST /payment-intents
Authorization: Bearer sk_test_...
Idempotency-Key: order-1234
Content-Type: application/json
{
"amount": 2500,
"reference": "order-1234",
"return_url": "https://you.example.com/thanks"
}
Response:
{
"intent": {
"id": "pi_...",
"status": "requires_action",
"next_action": {
"type": "redirect",
"url": "/simulate/pi_..."
}
}
}
The intent starts in requires_action. The next_action tells you what to do next, independent of which rail the payment uses.
4. Drive the Payment to Completion (Test Mode)
In test mode, every rail is simulated inside the aggregator. Use the transxact simulate command or the /simulate/ API endpoint.
Redirect Rails (M-PAiSA & Cards)
The customer is handed to a hosted page (Vodafone for M-PAiSA, gateway for cards). In test mode, you can simulate this locally:
transxact simulate:redirect pi_...
Input (via --magic flag) | Outcome |
|---|---|
reference: "test_success" or amount 1 | succeeded |
reference: "test_fail" or amount 2 | failed |
reference: "test_pending" | stays processing, then succeeds on next simulate |
MyCash (OTP Collection)
1. Create the intent with payment_method: "mycash" to receive next_action: { type: "collect_otp" }.
2. Relay the merchant's mobile number server-side:
transxact payments:confirm \
--id pi_... \
--mobile "+6799997888"
3. Confirm the OTP:
transxact payments:confirm \
--id pi_... \
--otp "123456"
Magic values: Any OTP approves except
000000(forcesotp_incorrect). The magic mobile+679 999 7888forcespayment_error.
Why the polymorphic next_action?
The merchant never sees which rail or gateway a payment uses. They see redirect or collect_otp and the same status transitions (requires_action → processing → succeeded | failed). This is the core of Transxact's "one integration, all rails" promise.
5. Verify the Webhook
You'll receive signed webhook notifications for payment events. The aggregator pushes these to your endpoint.
Register a webhook endpoint
transxact webhooks:create \
--url "https://you.example.com/hooks/transxact"
The response returns a secret — store it securely. An unverified endpoint is marked active only after it returns 2xx to the webhook.verified event.
Verify incoming webhooks
Each delivery includes:
Transxact-Signature: v1=<hex>headerTransxact-Timestamp: <unix-seconds>headerX-Transxact-Event-Id: evt_...header in the payload
The signature is HMAC-SHA256("<timestamp>.<body>") with your webhook secret. Reject any delivery whose timestamp is older than 5 minutes (replay window).
Expected webhook events
| Event | When it's sent |
|---|---|
webhook.verified | Once, immediately after endpoint registration/updated secret |
payment.processing | When the intent transitions to processing |
payment.succeeded | When the intent reaches succeeded status |
payment.failed | When the intent reaches failed status |
disbursement.sent | After the daily disbursement run |
disbursement.failed | If a disbursement bounces |
Deduplication: Each delivery carries
X-Transxact-Event-Idplus theevent_idin the payload. Use both to idempotently process events.
6. Go Live — Transition from Test to Live Mode
When you're ready to process real payments:
1. Ensure your risk tier allows live mode (all tiers can go live, but High tier may have additional CDD requirements).
2. Enable the rails you want to support via the Transxact Dashboard → Rail config.
3. Create live-mode keys:
transxact keys:create --mode live
4. Test each rail in live mode using the real test endpoints (see scripts/setup-mpaisa.sh and scripts/setup-mycash.sh for credential setup).
5. Monitor the first disbursement — the aggregator pays sub-merchants daily (T+1), net of rail fees.
Rail-specific live notes:
- M-PAiSA: Redirect to Vodafone's hosted page; aggregator verifies
tokenv2/authdigestv2SHA-256 callback before pollingrequeststatusto terminal.- MyCash: Server-to-server
paymentRequest → sendOTP → approvePaymentflow. Live mode requires rail credentials.- Cards: Redirect to gateway-hosted payment page (Windcave/MPGS).
7. Build Payment Links (Optional)
If you want to share a payment URL with customers:
transxact payment-links:create \
--type single_use \
--amount 2500 \
--reference "inv-1"
- Single-use link: Fixed amount, consumed on first successful payment. Refuses a second visit after use.
- Reusable "pay me" link: No pre-set amount; customer enters any amount at checkout.
The response's url is the hosted checkout, presenting the shopper a method list (M-PAiSA, MyCash, card) and driving the payment in test or live mode.
Next Steps
- Read the full API reference:
docs/api/openapi.yaml(the single source of truth, ADR-0006). - Explore the SDKs: Twelve first-party client libraries (per ADR-0010) wrap the API with typed requests/responses, idempotency, retries, webhook signature verification, and test-mode magic-value helpers.
- Join the community: Check the Developer section of the Transxact Dashboard for the magic-value cheatsheet, webhook endpoint management, and links to docs and the OpenAPI spec.
- Troubleshooting: If you hit
requires_actionthat won't resolve, check thenext_actiontype and rail-specific test-mode magic values above. If you receive unexpected webhook events, consult theEvent delivery login the Developer section for delivery attempts and response codes.
Footnotes
1. Test mode vs staging: Test mode is fully simulated inside the aggregator (ADR-0005). Staging is the aggregator's own environment wired to the rails' real test endpoints — internal-only, never exposed to merchant developers.
2. Error object: Every API error has a closed type set (invalid_request, authentication_error, permission_error, idempotency_error, rate_limit_error, api_error, payment_error) and a machine-readable code (e.g. amount_too_small, intent_already_succeeded, otp_incorrect). Human message may change; receivers must not reject unknown fields (additive-only contract, ADR-0013).
3. Versioning: Omitting Transxact-Version header pins to the current default (2026-08-16). New fields are additive and never break a pinned integration.
Next steps
API reference — every endpoint with its parameters, response schema, error codes, and per-language examples.
Developer section — create keys, manage webhook endpoints, and watch the delivery log.