Built for developers.

One server-to-server REST API for the FlowAcq orchestration layer. Start with sandbox and the Stripe-live path, read normalized results, and verify signed webhooks. Broader provider routing is staged behind approvals.

Quickstart guideAPI referenceConnector coverage

01 - Send a charge

One request, normalized result

FlowAcq is an orchestration layer, not a processor. You send one JSON charge; FlowAcq screens it for fraud, applies the configured live provider path, and returns a normalized result synchronously. Pass a tokenized payment method as paymentMethodToken - never raw card data - and an idempotencyKey so retries are safe.

Amounts are in the currency's minor units (4200 = $42.00). Authenticate every request with the x-api-key header: a ps_test_... key hits sandbox, a ps_live_... key hits live.

curl https://api.flowacq.com/v1/orchestration/charge \
  -H "x-api-key: ps_test_xxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: order_a1b2c3" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4200,
    "currency": "USD",
    "paymentMethodToken": "pm_card_visa",
    "idempotencyKey": "order_a1b2c3",
    "metadata": { "orderId": "A-10294" }
  }'

02 - Read the result

A consistent ChargeResult

The endpoint responds 200 OK with a normalized ChargeResult: a FlowAcq transactionId, the underlying pspTransactionId, a status from the unified lifecycle, and the amounts.

Declines come back with success: false plus an errorCode, errorMessage, and retryable flag. The response contract stays consistent as approved provider routes are added.

HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "transactionId": "txn_9f2c1a90b3",
  "pspTransactionId": "ch_3Pd_example_stripe",
  "status": "CAPTURED",
  "authorizedAmount": 4200,
  "capturedAmount": 4200
}

03 - Or use the SDK

@paysys/sdk for TypeScript

The @paysys/sdk is a small server-side helper. It attaches your x-api-key, JSON headers, and the Idempotency-Key for mutating calls, and types every response. It intentionally exposes only server-side helpers - never ship a secret API key to a browser.

Beyond charge, the client covers refunds, hosted checkout-session records, webhook endpoints, and route-rule surfaces. Some live behavior remains dependent on provider approval.

import { PaySysClient } from "@paysys/sdk";

const paysys = new PaySysClient({
  apiKey: process.env.PAYSYS_API_KEY!,
  baseUrl: process.env.PAYSYS_API_URL,
});

const result = await paysys.charge(
  {
    amount: 4200,
    currency: "USD",
    paymentMethodToken: "pm_card_visa",
    metadata: { orderId: "A-10294" },
  },
  "order_a1b2c3",
);

if (result.success) {
  console.log(result.transactionId, result.status);
}

04 - Verify webhooks

HMAC-signed, every time

Every event FlowAcq delivers carries an x-paysys-signature header - an HMAC-SHA256 of the raw body, keyed with your endpoint's signing secret. Recompute it over the exact bytes you received and compare in constant time before trusting the payload.

The SDK's verifyPaySysWebhookSignature does this for you. Deliveries are logged with payload and response, with one-click replay in the dashboard so you can re-drive any event while you build.

import { verifyPaySysWebhookSignature } from "@paysys/sdk";

export function handlePaySysWebhook(req) {
  const ok = verifyPaySysWebhookSignature({
    rawBody: req.rawBody,
    signature: req.headers["x-paysys-signature"],
    signingSecret: process.env.PAYSYS_WEBHOOK_SECRET!,
  });

  if (!ok) {
    return new Response("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(req.rawBody);
}

Quickstart

  • Create an API key in your dashboard under API Keys - start with a ps_test_... key. API Keys
  • Tokenize a payment method and POST it to /v1/orchestration/charge with an idempotencyKey.
  • Register a webhook endpoint and verify the x-paysys-signature on each delivery.
  • Swap to a ps_live_... key only after KYB, provider credentials, live terms, and fee approval are complete.

Verify it yourself

Prefer no dependency? The signature is a plain hex HMAC-SHA256 over the raw body - recompute and constant-time compare in any language.

const crypto = require("crypto");

const expected = crypto
  .createHmac("sha256", endpointSigningSecret)
  .update(rawBody)
  .digest("hex");

const ok = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(req.headers["x-paysys-signature"]),
);

Sandbox mirrors live exactly - same endpoints, same payloads - with no money moved. Need something specific? Talk to us.