Sayfin API Reference
Sayfin is a real-time predictive intelligence layer for payments. The API receives a transaction payload and responds with an optimized routing recommendation, behavioral scores, and confidence metrics — all in under 15ms.
All requests are made over HTTPS. The API returns JSON. Authentication uses HMAC-SHA256 request signing.
p99 latency under 15ms. Sayfin is designed for inline transaction flows — every millisecond counts and we guarantee it.
Authentication
All API requests must be signed using HMAC-SHA256. Your API key and secret are provisioned during onboarding. Every request requires three headers:
| Header | Type | Description |
|---|---|---|
| X-Sayfin-Key | string | Your API key (begins with sk_) |
| X-Sayfin-Timestamp | integer | Unix timestamp in ms (must be within 30s of server time) |
| X-Sayfin-Signature | string | HMAC-SHA256 of timestamp + "." + body using your secret |
Generating a Signature
# pip install sayfin
import hmac, hashlib, time, json
def sign_request(secret: str, body: dict) -> dict:
ts = str(int(time.time() * 1000))
payload = ts + "." + json.dumps(body, separators=(",", ":"))
signature = hmac.new(
secret.encode(), payload.encode(), hashlib.sha256
).hexdigest()
return {
"X-Sayfin-Key": "sk_live_...",
"X-Sayfin-Timestamp": ts,
"X-Sayfin-Signature": signature,
"Content-Type": "application/json",
}
import crypto from "crypto";
function signRequest(secret: string, body: object) {
const ts = Date.now().toString();
const payload = ts + "." + JSON.stringify(body);
const sig = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return {
"X-Sayfin-Key": "sk_live_...",
"X-Sayfin-Timestamp": ts,
"X-Sayfin-Signature": sig,
};
}
Base URL & Versioning
Production: https://api.sayfin.ai/v1
Sandbox: https://sandbox.sayfin.ai/v1
The current API version is v1. Breaking changes will be introduced as new versions (v2, v3) with a minimum 6-month deprecation window. Non-breaking additions (new fields, new endpoints) are added without versioning.
POST /v1/route
The primary endpoint. Receives a transaction and returns the optimal acquirer routing with probability scores and behavioral context. Designed for inline pre-authorization placement.
Request Body
| Field | Type | Description |
|---|---|---|
| transaction_idrequired | string | Your unique transaction identifier |
| amountrequired | integer | Amount in minor units (e.g. pence, cents) |
| currencyrequired | string | ISO 4217 currency code (e.g. GBP, USD, EUR) |
| card_binrequired | string | First 6–8 digits of the card number |
| merchant_idrequired | string | Your merchant identifier |
| cardholder_id | string | Stable identifier for the cardholder (for behavioral scoring) |
| geo | string | ISO 3166-1 alpha-2 country code of the transaction origin |
| channel | string | web, mobile, pos, or api |
| metadata | object | Arbitrary key/value pairs passed through to the response |
Example Request
{
"transaction_id": "txn_8f2k9d",
"amount": 284700,
"currency": "GBP",
"card_bin": "483204",
"merchant_id": "mer_xyz",
"cardholder_id": "usr_ab91c",
"geo": "GB",
"channel": "web"
}
Example Response
{
"route": {
"acquirer": "acquirer_b",
"probability": 0.943,
"confidence": "high"
},
"alternatives": [
{ "acquirer": "acquirer_a", "probability": 0.871 },
{ "acquirer": "acquirer_c", "probability": 0.714 }
],
"behavioral": {
"segment": "high_value",
"trust_score": 0.91,
"is_recurring": true,
"anomaly_flag": false
},
"latency_ms": 7.2,
"request_id": "req_4af91b"
}
GET /v1/recommendations
Returns aggregated routing recommendations for a merchant over a time window. Useful for analytics dashboards and weekly optimization reports.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| merchant_idrequired | string | Merchant to query |
| from | string | ISO 8601 start datetime (default: 7 days ago) |
| to | string | ISO 8601 end datetime (default: now) |
| granularity | string | hour, day, or week (default: day) |
curl -G https://api.sayfin.ai/v1/recommendations \
-H "X-Sayfin-Key: sk_live_..." \
-H "X-Sayfin-Signature: ..." \
-H "X-Sayfin-Timestamp: 1706188800000" \
--data-urlencode "merchant_id=mer_xyz" \
--data-urlencode "granularity=day"
POST /v1/feedback
Submits the actual transaction outcome back to Sayfin. This closes the feedback loop and is what enables continuous model retraining. Strongly recommended for all processed transactions.
| Field | Type | Description |
|---|---|---|
| transaction_idrequired | string | Must match the ID from the original /route call |
| outcomerequired | string | approved, declined, or soft_declined |
| acquirer_used | string | Acquirer that actually processed the transaction |
| decline_code | string | Issuer or network decline code (if applicable) |
| settled_at | string | ISO 8601 datetime of settlement |
Sending feedback within 2 hours of transaction authorization maximizes model learning speed. Feedback can be batched — send up to 500 outcomes per call.
POST /v1/compare
Compare predicted approval probabilities between two acquirers for a given transaction profile. Used in shadow-mode testing and A/B routing experiments.
{
"transaction_id": "txn_cmp_01",
"amount": 150000,
"currency": "USD",
"card_bin": "412345",
"acquirers": ["acquirer_a", "acquirer_b"]
}
{
"comparison": [
{ "acquirer": "acquirer_a", "probability": 0.871, "rank": 2 },
{ "acquirer": "acquirer_b", "probability": 0.943, "rank": 1 }
],
"recommended": "acquirer_b",
"delta": 0.072
}
Error Handling
All errors follow a consistent JSON structure. HTTP status codes map to error categories.
{
"error": {
"code": "invalid_signature",
"message": "HMAC signature does not match",
"status": 401,
"request_id": "req_err_7x2"
}
}
| Status | Code | Description |
|---|---|---|
| 400 | invalid_body | Request body is malformed JSON or missing required fields |
| 401 | invalid_signature | HMAC signature verification failed |
| 401 | expired_timestamp | X-Sayfin-Timestamp is more than 30s from server time |
| 403 | forbidden | API key does not have access to this endpoint |
| 404 | not_found | Referenced resource (e.g. transaction_id) does not exist |
| 429 | rate_limited | Rate limit exceeded — see Retry-After header |
| 500 | internal_error | Sayfin internal error — automatically retried |
On 500 errors, implement exponential backoff with a maximum of 3 retries. For 429 errors, respect the Retry-After response header exactly.
Rate Limits
Rate limit headers are included in every response:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Your configured requests/sec limit |
| X-RateLimit-Remaining | Requests remaining in the current second |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| Retry-After | Seconds to wait before retrying (only on 429) |
SDKs
Official SDKs are available for Python and TypeScript. Both are async-first, fully typed, and handle signing automatically.
# Install
pip install sayfin
# Usage
from sayfin import Sayfin
client = Sayfin(api_key="sk_live_...", secret="...")
result = await client.route(
transaction_id="txn_8f2k9d",
amount=284700,
currency="GBP",
card_bin="483204",
merchant_id="mer_xyz",
)
print(result.route.acquirer) # "acquirer_b"
// Install
npm install @sayfin/sdk
// Usage
import { Sayfin } from "@sayfin/sdk";
const client = new Sayfin({ apiKey: "sk_live_...", secret: "..." });
const result = await client.route({
transactionId: "txn_8f2k9d",
amount: 284700,
currency: "GBP",
cardBin: "483204",
merchantId: "mer_xyz",
});
console.log(result.route.acquirer); // "acquirer_b"
Changelog
v1.3.0 — February 2026
Added behavioral object to /v1/route response including trust_score, segment classification, and anomaly_flag. New cardholder_id field enables per-user behavioral model.
v1.2.0 — December 2025
Introduced batch feedback support (up to 500 outcomes per /v1/feedback call). Reduced p99 latency from 18ms to 11ms through model architecture improvements.
v1.1.0 — October 2025
Added /v1/compare endpoint for A/B acquirer testing. HMAC signature window extended from 15s to 30s for clock-skew tolerance.
v1.0.0 — August 2025
Initial release. Core /v1/route endpoint, HMAC-SHA256 authentication, Python and TypeScript SDKs.