Track A · developer guide
Library-first integrator guide
End-to-end steps for merchants running PayWay on their own server. Hosted cloud API is optional Track B — see /docs/guide.
End-to-end checklist
- Install the package for your stack (NuGet / npm / pip / Composer / Woo plugin).
- Fill sandbox SSL and/or bKash credentials in appsettings / .env / Woo settings.
- Set absolute success, fail, cancel, and IPN URLs on your public hostname (tunnel for local IPN).
- Call
CreateCharge→ persistsessionId↔ order → redirect tocheckoutUrl. - Complete a sandbox payment; confirm IPN/callback hits your endpoint and marks the order paid.
- Go live: flip sandbox flags off; whitelist this server's public IP for SSLCommerz.
- Optionally point license + control plane URL at your activation service (fail-open if down).
Credentials — what goes where
Paste provider secrets into config or the portal. Never commit them to git.
| Provider | From provider | PayWay / SDK keys |
|---|---|---|
| SSLCommerz | Store ID → StoreIdStore Password → StorePasswordSandbox toggle → IsSandbox | Hosted guide · repo docs/20-sslcommerz-credentials-map.md |
| bKash | app_key → AppKeyapp_secret → AppSecretusername → Usernamepassword → PasswordExecute/Query body → paymentId (not callback paymentID) — guide | Hosted guide · repo docs/19-bkash-credentials-map.md |
Portal UI: /credentials. Customer wallet OTP/PIN (bKash) and card data (SSL) are not PayWay credential fields.
Unified API
| Action | .NET | Node / PHP / Python |
|---|---|---|
| Create charge | CreateChargeAsync | createCharge / create_charge |
| SSL IPN | HandleSslCommerzIpnAsync | handleSslIpn / handle_ssl_ipn |
| bKash callback | HandleBkashCallbackAsync | handleBkashCallback / handle_bkash_callback |
Do not trust browser return alone. Fulfill only after IPN/callback (or provider verify).
GetCharge memory is process-local — use your DB.Config reference
{
"PayWay": {
"PreferredGateway": "auto",
"AllowFailover": true,
"Urls": {
"Success": "https://shop.example.com/pay/success",
"Fail": "https://shop.example.com/pay/fail",
"Cancel": "https://shop.example.com/pay/cancel",
"Ipn": "https://shop.example.com/pay/ipn/ssl"
},
"SslCommerz": {
"Enabled": true,
"IsSandbox": true,
"StoreId": "YOUR_STORE_ID",
"StorePassword": "YOUR_STORE_PASSWORD",
"Priority": 10
},
"Bkash": {
"Enabled": true,
"IsSandbox": true,
"AppKey": "…",
"AppSecret": "…",
"Username": "…",
"Password": "…",
"Priority": 20
}
}
}Failover rules
PreferredGateway = autotries lowerPriorityfirst.- Failover only on timeout / network / HTTP 5xx.
- No failover on user cancel, decline, or validation errors.
Security & ops
- Never put gateway secrets in browser bundles or mobile apps.
- Log session / order / gateway / provider txn ids — never store passwords in logs.
- Control plane events: no secrets, no PII.
- License unreachable → charges still succeed (fail-open).
Optional control plane
cd src/control && dotnet run
# http://localhost:5090
# Demo license: demo-license-change-me
# POST /v1/activation/validate
# POST /v1/events/transactionsPlatform notes
| Platform | Sample path |
|---|---|
| ASP.NET Web Forms | packages/samples/library-first/csharp-webforms/ |
| ASP.NET MVC 5 | packages/samples/library-first/csharp-mvc/ |
| ASP.NET Core | packages/samples/library-first/csharp-aspnetcore/ |
| Node Express | packages/samples/library-first/node-express/ |
| Python Flask | packages/samples/library-first/python/ |
| PHP | packages/samples/library-first/php/ |
| WooCommerce | packages/samples/library-first/woocommerce/ |
Error codes (.NET)
| Code | Meaning |
|---|---|
VALIDATION_ERROR | Bad amount, missing orderId/URLs, non-BDT |
NO_ROUTE | No enabled credentials for preferred gateway |
GATEWAY_UNAVAILABLE | All attempts failed after optional failover |