Fortion
Contact
Developers / API v1

Fortion API documentation

Add hosted pay-ins and controlled payout requests to your server. Fortion keeps provider credentials, routing and payment status inside one orchestration layer.

Base URLhttps://fortionps.com
AuthenticationBearer integration token
Payloadsapplication/json
Current payout scope

The API creates a payout request for review. Fortion does not automatically transfer funds, hold a merchant balance or create an internal ledger entry in the current version.

Integration guide

Connect a merchant in five steps

Use one shop for one merchant payment context. The shop owns its routes, integration tokens and webhook secret, so credentials never need to cross company boundaries.

  1. 1

    Prepare the shop

    Ask Fortion to activate the company, shop and at least one payment route.

  2. 2

    Create server credentials

    In Merchant Admin open the shop → Integration. Add a public HTTPS endpoint, create a webhook secret, then create a server key with “Pay-ins and payouts” permissions.

  3. 3

    Create a payment

    Send one server request and redirect the customer to the returned checkoutUrl.

  4. 4

    Confirm the result

    Verify the signed webhook. A browser redirect is useful for UX, but is not proof of payment.

  5. 5

    Create payout requests

    Send safe recipient references only. Track review and execution status from your server.

Authentication

Keep both secrets on your server

The integration token authorizes API calls. The webhook secret verifies events sent by Fortion. Both are displayed only once and must remain server-side only.

Never expose a token in browser code

Your frontend calls your own backend. Your backend calls Fortion with the Authorization: Bearer … header.

Authorization header
Authorization: Bearer sdk.sit_xxx.your_secret
Content-Type: application/json

Permissions

orders:createCreate and start a pay-in
orders:readRead pay-in status
payouts:createCreate a payout request
payouts:readRead payout status
POST /sdk/orders

Create and start a payment

The shortest valid request has three business fields. If the shop has one default route, paymentSelection is not required.

cURL
curl https://fortionps.com/sdk/orders \
  -X POST \
  -H "Authorization: Bearer $FORTION_INTEGRATION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalOrderId": "order_1001",
    "productName": "Pro plan",
    "amount": 199
  }'

Response

201 Created
{
  "order": {
    "id": "ord_abc123",
    "externalOrderId": "order_1001",
    "status": "in_progress"
  },
  "checkoutUrl": "https://fortionps.com/pay/random-checkout-token",
  "reusedExistingOrder": false
}
Currency is configured on the shop route

The current pay-in request does not select a currency per order. Confirm the shop currency before launch.

GET /sdk/orders/by-external/:externalOrderId

Read a payment by your identifier

Store your externalOrderId and use it for recovery or support. Webhooks remain the preferred source of terminal status.

cURL
curl "https://fortionps.com/sdk/orders/by-external/order_1001" \
  -H "Authorization: Bearer $FORTION_INTEGRATION_TOKEN"
createdOrder exists, payment has not started in_progressCustomer or provider action is pending completedPayment completed failedPayment failed
GET /sdk/available-payment-routes

List available payment routes

Call this only when your product lets a customer select a method. Otherwise omit paymentSelection and let the shop default route decide.

POST /sdk/payouts

Create a payout request

This endpoint records merchant intent and returns pending_review. It does not execute a bank, wallet or crypto transfer automatically.

cURL
curl https://fortionps.com/sdk/payouts \
  -X POST \
  -H "Authorization: Bearer $FORTION_INTEGRATION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalPayoutId": "payout_1001",
    "amount": 125000,
    "currency": "UZS",
    "country": "UZ",
    "methodType": "bank_transfer",
    "recipient": {
      "reference": "recipient_42",
      "displayName": "Example LLC",
      "maskedDestination": "****1234"
    }
  }'
Do not send raw financial credentials

Card numbers, CVV, full bank account numbers and IBAN values are rejected. Send your internal recipient reference and an already-masked destination only. Use opaque alphanumeric identifiers such as payout_1001; any field containing 12 or more consecutive digits is rejected as potentially sensitive destination data.

Current country and currency pairs

CountryCurrency
Uzbekistan · UZUZS
Kyrgyzstan · KGKGS
GET /sdk/payouts/by-external/:externalPayoutId

Read payout status

Use your externalPayoutId for reconciliation. The response separates request review from execution state so a reviewed request is never confused with moved funds.

pending_reviewWaiting for an operator decision approvedApproved for controlled execution rejectedRejected with a safe reason code when available completedManual execution was recorded as succeeded
Events

Trust signed webhooks, not redirects

Fortion sends JSON events to the shop’s public HTTPS endpoint. Return 2xx only after your system persists the event. Failed deliveries are retried from a durable queue.

payment.completedA pay-in reached terminal success
payment.failedA pay-in reached terminal failure
payout.updatedA payout review or execution state changed
subscription.updatedSubscription compatibility event

Headers

Webhook request
x-fortion-event-id: mwe_123
x-fortion-event-type: payment.completed
x-fortion-signature-timestamp: 2026-07-28T12:00:00.000Z
x-fortion-signature: v1=<hex>
Webhook security

Verify HMAC SHA-256 on the raw body

Build the signed value as ${timestamp}.${rawBody}. Reject timestamps older than five minutes and process every event idempotently by event ID.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyFortionWebhook({ rawBody, timestamp, signature, secret }) {
  if (!signature?.startsWith("v1=")) return false;

  const age = Math.abs(Date.now() - Date.parse(timestamp));
  if (!Number.isFinite(age) || age > 5 * 60 * 1000) return false;

  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`, "utf8")
    .digest("hex");
  const received = signature.slice(3);
  const left = Buffer.from(received, "hex");
  const right = Buffer.from(expected, "hex");

  return left.length === right.length && timingSafeEqual(left, right);
}
Reliability

Retry with the same merchant identifier

For both pay-ins and payouts, the same identifier and the same payload return the existing resource. The same identifier with a different payload returns 409 Conflict.

externalOrderId

Unique inside one shop. Reuses the same order and active payment session.

externalPayoutId

Unique inside one shop. Reuses the same payout request.

API reference

Handle errors by HTTP status

StatusMeaning
400Invalid request. Fix the fields before retrying.
401Missing, invalid or revoked token.
403The token does not have the required permission.
404Resource is not visible inside this shop.
409Route conflict or reused identifier with a different payload.
Test safely

Run the reference merchant locally

The repository includes a small merchant site that calls the same pay-in and payout endpoints from its backend. Copy the environment template, add a non-production token, then run:

Terminal
cd examples/merchant-quickstart
cp .env.example .env
npm start
Local webhooks are intentionally blocked

Fortion accepts only a public HTTPS endpoint, not localhost or a private IP. Test the handler locally with the signed fixture, then use a controlled public test endpoint for delivery testing.

Endpoints

API reference

Launch checklist

Before you go live

  • Use a separate token for each shop and environment.
  • Confirm the payment route, provider account and shop currency with Fortion.
  • Store the integration token and webhook secret in secret storage.
  • Verify webhook timestamp, signature and event ID before updating state.
  • Test a completed pay-in, a failed pay-in and an idempotent retry.
  • Confirm payout permissions and the manual review process with operators.
Discuss integration