kepa
GETTING STARTED

Client SDKs

Typed clients with idempotency, retries, and webhook verification built in.

Every Atlas SDK is built on top of the same REST and WebSocket surface you'd hit with raw HTTP, but it ships with the production-grade defaults baked in: automatic Idempotency-Key generation, retry with exponential backoff, webhook signature verification, and typed request/response models generated from the OpenAPI spec.

Available clients

Language
Package
Runtime targets
Status
TypeScript@atlas-softpos/sdkNode 18+, Deno, Bun, Cloudflare WorkersGA
Pythonatlas-softposPython 3.10+ (sync + async)GA
Kotlincom.atlas-softpos:sdkAndroid, JVM (bundled with Local Embedded kernel)BETA
SwiftAtlasSoftPOSiOS 16+, macOS 13+COMING SOON
Goatlas-softpos-goGo 1.22+COMING SOON
Rubyatlas_softposRuby 3.2+COMING SOON
C# / .NETAtlasSoftPOS.SDK.NET 8+ (many POS systems)COMING SOON

SDKs marked Coming Soon are in development. Request early access from your account manager or email [email protected].

TypeScript

install
npm install @atlas-softpos/sdk
# or
pnpm add @atlas-softpos/sdk
# or
yarn add @atlas-softpos/sdk

The TypeScript client is fully typed end-to-end. Every request and response comes straight from the OpenAPI spec, and the client handles idempotency, retries, and request IDs for you.

orchestrated sale
import { Atlas } from "@atlas-softpos/sdk";

const atlas = new Atlas({
  apiKey: process.env.ATLAS_API_KEY!,
  baseUrl: process.env.BASE_URL,      // defaults to https://api.atlas-softpos.com
  apiVersion: "2026-04-09",           // pin your integration
  timeout: 90_000,                    // 90s — orchestrated sales block
  maxRetries: 3,                      // automatic retry with same Idempotency-Key
});

// Orchestrated sale. Idempotency-Key is generated for you and reused across retries.
const result = await atlas.transactions.sale({
  amount: 2500,
  currency: "NZD",
  referenceId: "POS-INV-20260409-001",
  metadata: { cashier: "Jane", register: "REG-02" },
});

if (result.status === "APPROVED") {
  console.log("Auth code:", result.authorizationCode);
}

Granular mode feels the same — just a second call:

granular sale
// Granular mode — POS routes the auth itself.
const initiated = await atlas.granular.initiate({
  amount: 5000,
  currency: "NZD",
});

// Route to your own acquirer...
const issuerResponse = await myAcquirer.authorize(initiated.chipData);

// Hand the issuer response back to the terminal.
const final = await atlas.granular.complete({
  transactionId: initiated.transactionId,
  responseCode: issuerResponse.code,
  authorizationCode: issuerResponse.authCode,
  issuerAuthData: issuerResponse.authData,
});

Webhook signature verification is a one-liner. The helper throws if the signature is invalid or the timestamp is outside the replay window:

webhook receiver
import express from "express";
import { Atlas } from "@atlas-softpos/sdk";

const app = express();
app.use(express.raw({ type: "application/json" }));

app.post("/atlas-webhook", (req, res) => {
  try {
    const event = Atlas.webhooks.constructEvent(
      req.body,
      req.headers["atlas-signature"] as string,
      process.env.ATLAS_WEBHOOK_SECRET!,
    );

    switch (event.type) {
      case "transaction.settled":
        // ... reconcile in your system
        break;
      case "dispute.opened":
        // ... notify the merchant
        break;
    }

    res.status(200).end();
  } catch {
    res.status(401).end();
  }
});

Python

install
pip install atlas-softpos
# or
poetry add atlas-softpos
# or
uv add atlas-softpos

The Python client targets Python 3.10+ and supports both sync and async usage (atlas_softpos.aio). Same idempotency and retry defaults as TypeScript.

orchestrated sale
from atlas_softpos import Atlas

atlas = Atlas(
    api_key=os.environ["ATLAS_API_KEY"],
    base_url=os.environ.get("BASE_URL"),
    api_version="2026-04-09",
    timeout=90,
    max_retries=3,
)

# Orchestrated sale with automatic idempotency + retry.
result = atlas.transactions.sale(
    amount=2500,
    currency="NZD",
    reference_id="POS-INV-20260409-001",
    metadata={"cashier": "Jane", "register": "REG-02"},
)

if result.status == "APPROVED":
    print(f"Auth code: {result.authorization_code}")
webhook receiver (flask)
from flask import Flask, request, abort
from atlas_softpos import Atlas, SignatureVerificationError

app = Flask(__name__)
ATLAS_WEBHOOK_SECRET = os.environ["ATLAS_WEBHOOK_SECRET"]

@app.post("/atlas-webhook")
def atlas_webhook():
    try:
        event = Atlas.webhooks.construct_event(
            payload=request.get_data(),
            signature=request.headers["Atlas-Signature"],
            secret=ATLAS_WEBHOOK_SECRET,
        )
    except SignatureVerificationError:
        abort(401)

    if event.type == "transaction.settled":
        ...  # reconcile
    elif event.type == "dispute.opened":
        ...  # notify merchant

    return ("", 200)

Kotlin (Local Embedded)

The Kotlin SDK is different from the others — it includes the EMV kernel itself. Use it when you want the terminal to run inside your merchant app process rather than as a separate REST surface. See Connectivity & Flows for when to choose Local Embedded over Local Connected or Cloud.

Design principles

  • Zero boilerplate for the common path. If you can call raw HTTP, you can call the SDK. The defaults are production-grade.
  • Idempotency and retries on by default. Turn them off explicitly if you need to — never the other way around.
  • Generated from the OpenAPI spec. Every SDK is regenerated on every API release. Your types always match the server.
  • Typed webhook events. Discriminated unions on event.type so your switch statement is exhaustive at compile time.
  • Thin surface. SDKs don't add concepts, routing, or caching. They're a transport, not a framework.