satim-module - v1.0.0
    Preparing search index...

    satim-module - v1.0.0

    satim-sdk

    The stateless, secure, zero-dependency TypeScript SDK for the SATIM payment gateway.

    CIB and Edahabia card payments for Algeria — production-grade, runtime-agnostic, security-first.

    CI CodeQL License: MIT Node.js TypeScript Zero dependencies API Docs Discussions


    Warning

    This SDK has never been tested against a live production SATIM environment. It has been developed and validated exclusively against the SATIM test gateway (test.satim.dz) and simulated responses. Use in production entirely at your own risk. The authors and contributors accept no responsibility for payment failures, data loss, financial losses, or any other damages arising from the use of this software in any environment. Always perform your own end-to-end testing against the SATIM test gateway before going live.

    • Zero runtime dependencies. Just the Web Fetch API. No transitive supply chain.
    • Runs everywhere fetch runs. Node 20+, Bun, Deno, Cloudflare Workers, Vercel Edge.
    • Strictly immutable, fluent API. Every setter returns a new instance — no cross-request state leaks.
    • Security in depth by default. SSRF guards, credential isolation in a module-private WeakMap, terminal-ID injection prevention, IEEE 754-safe currency conversion, and a deliberately conservative retry policy that never double-charges.
    • Typed gateway errors. Discriminated SatimError subclasses with localized messages and a sanitized raw payload for logs (PII redacted).
    • Zero-trust webhooks. Built-in HMAC verification, replay protection, and rate limiting — designed for distributed deployments.
    • Strict TypeScript. Full type coverage, no any escape hatches in the public API.
    Runtime Version Notes
    Node.js ≥ 20 Native fetch required
    Bun ≥ 1.0
    Deno ≥ 1.28
    Cloudflare Workers All Edge-runtime safe
    Vercel / Netlify Edge All
    npm install satim-module
    # or
    bun add satim-module
    # or
    pnpm add satim-module
    import { Satim } from 'satim-module';

    const satim = new Satim({
    username: process.env.SATIM_USERNAME!,
    password: process.env.SATIM_PASSWORD!,
    terminalId: process.env.SATIM_TERMINAL_ID!,
    });

    // Register a payment
    const payment = await satim
    .amount(1500)
    .returnUrl('https://your-app.com/callback')
    .register();

    // Redirect the customer to the hosted payment page
    return payment.redirectResponse(); // standard Web API Response (302)
    const response = await satim.confirm(orderId, expectedCartTotal);

    if (response.isSuccessful()) {
    // Amount verification is automatic for successful payments
    console.log(response.getSuccessMessage());
    } else if (response.isPending()) {
    console.log('Payment not yet completed');
    } else if (response.isCancelled()) {
    console.log('Customer cancelled the payment');
    } else if (response.isExpired()) {
    console.log('Payment session expired');
    } else {
    console.log(response.getErrorMessage());
    }
    Method Endpoint Returns Description
    register() /register.do RegisterResponse Register a payment order.
    confirm(orderId, amount) /confirmOrder.do ConfirmResponse Confirm and deposit a payment.
    status(orderId) /getOrderStatus.do ConfirmResponse Query the current status of an order.
    refund(orderId, amount) /refund.do ConfirmResponse Refund a captured payment.
    registerPreAuth() /registerPreAuth.do RegisterResponse Hold funds without capturing.
    reverseOrder(orderId) /reverse.do ConfirmResponse Void a transaction before settlement.

    The configuration is strictly immutable. Calling a setter returns a NEW instance.

    Method Description
    amount(n) Payment amount in major currency units (e.g. DZD).
    returnUrl(url) Redirect URL after payment.
    failUrl(url) Redirect URL on failure (defaults to returnUrl).
    description(text) Text shown on the payment page (max 598 chars).
    language(lang) Payment page language: "FR", "AR", or "EN".
    currency(code) "DZD", "USD", or "EUR".
    orderNumber(n) Custom 10-digit order number.
    timeout(seconds) Session timeout (600 – 86400).
    userDefinedFields() Custom metadata forwarded in jsonParams.
    dynamicCallbackUrl() Server-to-server webhook for status notifications.
    setTestMode(bool) Route requests to test.satim.dz.

    All predicates are mutually exclusive — at most one terminal-state predicate will return true for any given response.

    Method Condition
    isSuccessful() Payment deposited (OrderStatus 2).
    isPending() Registered but not yet paid (OrderStatus 0).
    isReversed() Authorization reversed/voided (OrderStatus 3).
    isFailed() Terminal failure (not successful, refunded, or pending).
    isRejected() Declined by the issuing bank.
    isRefunded() Refunded (OrderStatus 4).
    isCancelled() Customer cancelled before completing.
    isExpired() Session timed out (actionCode -2007).

    Available on RegisterResponse or ConfirmResponse:

    Method Available On Returns
    getOrderId() RegisterResponse Order identifier
    getUrl() RegisterResponse Hosted payment form URL
    redirectResponse() RegisterResponse Web API 302 Response
    getIpAddress() ConfirmResponse Cardholder IP
    getCardHolderName() ConfirmResponse Name on card
    getCardExpiry() ConfirmResponse Expiration (YYYYMM)
    getCardPan() ConfirmResponse Masked PAN
    getApprovalCode() ConfirmResponse Issuer approval code
    getAmount() ConfirmResponse Payment amount captured
    getOrderNumber() ConfirmResponse Verified order number
    verifyAmount(n) ConfirmResponse Security assertion
    getSuccessMessage() ConfirmResponse Localized success text
    getErrorMessage() ConfirmResponse Localized error text
    getRawResponse() Both Sanitized raw gateway response (PII redacted)

    All errors extend SatimError for unified catching:

    import { SatimError, SatimGatewayError } from 'satim-module';

    try {
    await satim.register();
    } catch (err) {
    if (err instanceof SatimGatewayError) {
    // Typed BPC gateway error with err.errorCode and err.errorMessage
    // Code 1 = Duplicate order, 3 = Unknown currency,
    // 4 = Missing parameter, 7 = System error
    }
    if (err instanceof SatimError) {
    // SatimMissingDataError - required field not set
    // SatimInvalidArgumentError - validation failure
    // SatimInvalidCredentialsError - wrong username/password/terminal
    // SatimUnexpectedResponseError - network or malformed response
    // SatimGatewayError - typed BPC gateway errors (1,3,4,7)
    }
    }

    The SDK ships with the following protections enabled by default:

    • Credential isolation — Credentials live in a module-private WeakMap and never appear as enumerable properties. JSON.stringify() and console.log() automatically redact them. (The SATIM API requires credentials as POST form parameters on every request — make sure reverse proxies, WAFs, and APM tools do not log raw request bodies.)
    • SSRF protection — All URLs are validated against private IP ranges (IPv4/IPv6), cloud metadata endpoints, and non-standard IP encodings (decimal, octal, hex).
    • Terminal-ID injection preventionforce_terminal_id is always set by the SDK and cannot be overridden via userDefinedFields.
    • IEEE 754-safe currency conversion — Amounts are converted to minor units using toPrecision(12) to avoid floating-point drift. Sub-centime amounts that would round to zero are rejected. The precision guard caps at ~10 billion major units.
    • Safe retry policy — Financial mutations (register, confirm, refund, reverseOrder) never retry on transient errors, preventing double-charges or double-refunds. Only idempotent queries (status) retry automatically.
    • Immutable API — Every setter returns a new instance, preventing cross-request state leaks.
    1. Always verify server-side. Never trust client-side redirect parameters. Use confirm() or status() to verify outcomes from your backend.
    2. Always verify amounts. Call verifyAmount() to detect partial-payment manipulation.
    3. Use environment variables. Never hardcode credentials. Load them from process.env or a secrets manager.
    4. Never log request bodies. Outgoing POST bodies contain credentials; ensure logging middleware excludes them.
    5. Keep TLS valid. Never set NODE_TLS_REJECT_UNAUTHORIZED=0 in production.

    For the full threat model, see SECURITY.md.

    • ARCHITECTURE.md — system topology, request lifecycle, technical constraints, state machine, predicate contract.
    • src/README.md — module map and dependency order.
    • src/responses/README.md — response wrappers and the status predicate contract.
    • src/webhook/README.md — zero-trust verification flow and distributed deployment notes.
    • SECURITY.md — threat model, mitigations, known limitations.
    • API reference — generated locally with npm run docs (outputs to docs/api/).
    bun install       # install dev dependencies
    bun test # run the unit test suite (vitest)
    npm run typecheck # strict type checking (any runtime)
    npm run build # compile to dist/
    npm run docs # generate TypeDoc API reference

    Contributions are welcome. Please open an issue first for anything beyond a small fix so we can align on scope. PRs should:

    1. Keep the zero-dependency rule intact.
    2. Pass npm run typecheck and the full test suite.
    3. Include tests for behavioral changes.
    4. Follow the existing immutable, fluent API style.

    Released under the MIT License.