Skip to main content

Full Technical Documentation

Complete API reference including advanced usage, SLAs, and integration guides.

Download PDF
Getting Started

Sayfin API Reference

Version: v1.0.0  ·  Base URL: https://api.sayfin.ai  ·  Protocol: HTTP/HTTPS  ·  Content-Type: application/json

Sayfin sits between the PSP and the acquirer, not after the merchant. The PSP calls Sayfin to get routing recommendations before selecting an acquirer.

Merchant → PSP → [Sayfin] → Acquirer (Stripe/Adyen/etc.)

Average latency 7–8ms. p95 <15ms · p99 <25ms · Cold start ~58ms (first request after container start).

Authentication

All API requests are secured with HMAC-SHA256 signature-based authentication. Use our official SDKs to handle signing automatically, or implement manually for other languages.

Contact [email protected] or [email protected] to receive your api_key_id and api_secret via secure channel.

Required Headers

HeaderRequiredDescription
AuthorizationYesHMAC-SHA256 Signature={sig}, KeyId={api_key_id}
X-Request-TimestampYesUnix timestamp in seconds. Rejected if >5 minutes old.
Content-TypeYesMust be application/json

Step 1 — Create the Signature Message

Concatenate request details in this exact format:

{METHOD}\n{PATH}\n{BODY}\n{TIMESTAMP}

Example:
POST
/v1/recommendations
{"basic_info":{"transaction_id":"txn_001",...}}
1706356800

Step 2 — Calculate HMAC-SHA256

Python
import hmac, hashlib, time, json

timestamp = str(int(time.time()))
signature_message = f"POST\n/v1/recommendations\n{body}\n{timestamp}"

signature = hmac.new(
    api_secret.encode('utf-8'),
    signature_message.encode('utf-8'),
    hashlib.sha256
).hexdigest()
TypeScript
import crypto from "crypto";

const timestamp = Math.floor(Date.now() / 1000).toString();
const signatureMessage = `POST\n/v1/recommendations\n${body}\n${timestamp}`;
const signature = crypto
  .createHmac("sha256", API_SECRET)
  .update(signatureMessage)
  .digest("hex");

Step 3 — Include Headers

POST /v1/recommendations HTTP/1.1
Host: api.sayfin.ai
Content-Type: application/json
Authorization: HMAC-SHA256 Signature={signature}, KeyId={api_key_id}
X-Request-Timestamp: {timestamp}

Authentication Errors

StatusErrorFix
401Invalid signatureDouble-check your signature calculation
401Unknown keyVerify your api_key_id is correct
401Timestamp expiredRequest timestamp is >5 minutes old — use a current timestamp
403Key expiredContact us for a new key
403Key revokedContact [email protected]

Base URL & Versioning

https://api.sayfin.ai

API versioning is handled via URL path. The current version is v1. Breaking changes are released as new versions (v2, etc.). Non-breaking changes (new optional fields) may be added to existing versions without notice.

GET /health

GET /health

Check API and database connectivity. No authentication required. Rate limit: unlimited. Use for Kubernetes liveness/readiness probes and load balancer health checks.

cURL
curl https://api.sayfin.ai/health
StatusBodyMeaning
200 OKOKAPI and database healthy
503Service UnavailableDatabase unavailable

POST /v1/recommendations

POST /v1/recommendations

The primary endpoint. Returns the top 3 payment acquirer recommendations ranked by approval probability. Authentication: HMAC-SHA256. Rate limit: 100,000 req/min.

More fields = better ML accuracy. Include as many fields as available from your payment flow. The minimum required fields are transaction_id, amount, and currency_code.

Minimum Required Payload

JSON
{
  "basic_info": {
    "transaction_id": "txn_12345",
    "amount": 4.50,
    "currency_code": "USD"
  },
  "actor_info": {
    "merchant_id": "merchant_abc",
    "mcc": 5499
  },
  "card_data": {
    "entry_mode": "NFC",
    "brand_info": { "primary_description": "VISA" }
  }
}

Basic Info Fields

FieldTypeDescription
transaction_idrequiredstringUnique transaction identifier
amountrequiredfloatTransaction amount (e.g. 4.50)
currency_coderequiredstringISO 4217 uppercase (e.g. "USD", "EUR")
currency_numericstringISO 4217 numeric code (e.g. "840")
site_idintegerSite/location identifier
machine_au_timestringMachine authorization time
machine_au_time_exactstringExact ISO 8601 timestamp
timeout_msintegerRequest timeout in milliseconds (e.g. 15000)
payment_method_idintegerPayment method type identifier
billing_provider_idintegerBilling provider identifier
rrnstringRetrieval Reference Number

Actor Info (Merchant) — Recommended

FieldTypeDescription
merchant_idrequiredstringMerchant identifier
merchant_namestringMerchant business name
mccintegerMerchant Category Code (e.g. 5499, 5812)
merchant_countryobjectCountry object with name, numeric_code, alpha2_code, alpha3_code
geo_locationobjectGeographic location with state, city, country_code, zip_code, address, latitude, longitude
phone_numberstringMerchant phone number

Card Data — Recommended

FieldTypeDescription
masked_card_numberstringMasked PAN — never send full PAN (e.g. "411111xxxxxx1234")
entry_modestring"NFC", "Chip", "Swipe", or "Manual"
exp_yearstringExpiration year YY (e.g. "30")
exp_monthstringExpiration month MM (e.g. "12")
brand_infoobjectCard brand: primary_id, primary_description, secondary_id
is_debit_cardbooleanWhether card is debit vs credit

Response

200 OK · ~7ms
{
  "transaction_id": "txn_12345",
  "recommendations": [
    { "acquirer": "Adyen",        "probability": 0.92, "rank": 1 },
    { "acquirer": "Stripe",       "probability": 0.05, "rank": 2 },
    { "acquirer": "Checkout.com", "probability": 0.02, "rank": 3 }
  ],
  "model_version": "v1.0.0",
  "timestamp": "2025-12-27T21:00:00Z"
}

SDK Examples

Python SDK
from sayfin import SayFin

client = SayFin(api_key="your_api_key_id", api_secret="your_api_secret")
rec = client.get_recommendations({...})
print(rec.recommendations[0].acquirer)   # "Adyen"
print(rec.recommendations[0].probability) # 0.92
TypeScript SDK
import { SayFin } from "@sayfin/sdk";

const client = new SayFin({ apiKey: "your_api_key_id", apiSecret: "your_api_secret" });
const rec = await client.getRecommendations({...});
console.log(rec.recommendations[0].acquirer); // "Adyen"

POST /v1/feedback

POST /v1/feedback

Submit transaction outcome feedback for model retraining and accuracy tracking. Authentication: HMAC-SHA256. Rate limit: 100,000 req/min per merchant.

Request Body

FieldTypeDescription
transaction_idrequiredstringMust match a previous /v1/recommendations request
acquirer_usedrequiredstringWhich acquirer was actually used (e.g. "Adyen")
outcomerequiredstring"approved", "declined", or "error"
processing_time_msintegerProcessing time in milliseconds
recommended_rank_usedintegerWhich recommendation rank was used: 1, 2, or 3
Request
{
  "transaction_id":       "txn_12345",
  "acquirer_used":        "Adyen",
  "outcome":              "approved",
  "processing_time_ms":   250,
  "recommended_rank_used": 1
}

Response

200 OK
{
  "feedback_id":    42,
  "transaction_id": "txn_12345",
  "status":         "accepted"
}

Use cases: track recommendation accuracy · measure which rank is typically used · collect data for model retraining · monitor approval rates per acquirer. Returns 409 Conflict if feedback was already submitted for a transaction.

POST /v1/compare

POST /v1/compare

Compare PSP's acquirer choice against the model's top recommendation. Validate if manual routing aligns with the model, measure adoption rate, and A/B test routing strategies. Rate limit: 1,000 req/min.

Request Body

FieldTypeDescription
transaction_idrequiredstringMust match a previous /v1/recommendations request
acquirer_usedrequiredstringWhich acquirer was actually used
200 OK — Match Found
{
  "transaction_id":         "txn_12345",
  "match_found":            true,
  "predicted_rank":         1,
  "predicted_probability":  0.92,
  "all_recommendations": [
    { "acquirer": "Adyen",        "probability": 0.92, "rank": 1 },
    { "acquirer": "Stripe",       "probability": 0.05, "rank": 2 },
    { "acquirer": "Checkout.com", "probability": 0.02, "rank": 3 }
  ]
}

When the acquirer used is not in the top 3, match_found is false and predicted_rank / predicted_probability are null. Returns 404 if no recommendations exist for the given transaction ID.

Error Handling

All errors follow a consistent JSON structure. HTTP status codes map to error categories.

Error Response
{
  "error":   "Invalid HMAC signature",
  "details": "Signature mismatch for key sk_live_..."
}
StatusDescription
400Request body is malformed JSON or missing required fields
401HMAC signature verification failed or timestamp outside 5-minute window
403API key does not have access to this endpoint
404Referenced resource (e.g. transaction_id) does not exist
429Rate limit exceeded - see Retry-After header
500Sayfin internal error - implement exponential backoff

On 500 errors, implement exponential backoff with a maximum of 3 retries. For 429 errors, respect the Retry-After response header exactly.

Rate Limits

100Kreq/min (recommendations)
100Kreq/min (feedback)
1Kreq/min (compare)
5 minsignature window

The GET /health endpoint is not rate limited. Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitYour configured requests/min limit
X-RateLimit-RemainingRequests remaining in the current minute
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying (only on 429)

SDKs

Official SDKs are available for Python and TypeScript. Both are async-first, fully typed, and handle HMAC signing automatically.

Python SDK
# Install
pip install sayfin

# Usage
from sayfin import SayFin

client = SayFin(api_key="sk_live_...", api_secret="...")

result = await client.recommendations(
    transaction_id="txn_8f2k9d",
    amount=284700,
    currency="GBP",
    merchant_id="mer_xyz",
)
print(result.recommendations[0].acquirer_id)  # "acquirer_b"
TypeScript SDK
// Install
npm install @sayfin/sdk

// Usage
import { SayFin } from "@sayfin/sdk";

const client = new SayFin({ api_key: "sk_live_...", api_secret: "..." });

const result = await client.recommendations({
  transaction_id: "txn_8f2k9d",
  amount: 284700,
  currency: "GBP",
  merchant_id: "mer_xyz",
});
console.log(result.recommendations[0].acquirer_id); // "acquirer_b"