Skip to main content
WEBHOOK
CARD_AUTHORIZATION_VERIFY
{
  "event":      "CARD_AUTHORIZATION_VERIFY",
  "eventId":    "evt_01HXYZ987654FEDCBA",
  "businessId": "BUS1A2B3C4D5E6F",
  "timestamp":  "2026-05-27T14:32:00Z",
  "data": {
    "type":            "AUTHORIZATION",
    "cardId":          "crd_01HXYZ5555ABCDEF1111",
    "cardholderId":    "chl_01HXYZ1234ABCDEF5678",
    "amount":          42.50,
    "feeAmount":       1.25,
    "currency":        "USD",
    "merchantName":    "Amazon",
    "merchantMcc":     "5999",
    "merchantCountry": "US",
    "isOneTimeUse":    false,
    "timestamp":       "2026-05-27T14:32:01Z"
  }
}
{
  "decision": "APPROVE"
}
Fires synchronously whenever a cardholder action requires your approval. Fyatu forwards the request to your registered endpoint and waits up to 1.2 seconds for your APPROVE or DECLINE response. Your decision is sent back to the card network immediately — the cardholder experiences no perceptible delay.
You must respond within 1.2 seconds. If your endpoint does not respond in time, Fyatu automatically approves the request (fail-open). Design your handler to be fast — do not call slow external services in the critical path.

Event Type

CARD_AUTHORIZATION_VERIFY

When It Fires

This event fires for two distinct actions, distinguished by the type field in data:
data.typeWhat it meansFyatu balance gate
AUTHORIZATIONA cardholder is making a purchase (JIT charge)Yes — program balance must be ≥ amount + feeAmount. Fyatu auto-declines if insufficient and does not call your endpoint.
AUTHORIZATION_VERIFYA cardholder is adding their card to Apple Pay or Google Pay (tokenization)Yes — program balance must be ≥ $1.00. Fyatu auto-declines if insufficient and does not call your endpoint.
Both require the same response format from your server.

Payload

{
  "event":      "CARD_AUTHORIZATION_VERIFY",
  "eventId":    "evt_01HXYZ987654FEDCBA",
  "businessId": "BUS1A2B3C4D5E6F",
  "timestamp":  "2026-05-27T14:32:00Z",
  "data": {
    "type":            "AUTHORIZATION",
    "cardId":          "crd_01HXYZ5555ABCDEF1111",
    "cardholderId":    "chl_01HXYZ1234ABCDEF5678",
    "amount":          42.50,
    "feeAmount":       1.25,
    "currency":        "USD",
    "merchantName":    "Amazon",
    "merchantMcc":     "5999",
    "merchantCountry": "US",
    "isOneTimeUse":    false,
    "timestamp":       "2026-05-27T14:32:01Z"
  }
}

Payload Fields

FieldTypeDescription
typestringAUTHORIZATION for a purchase, AUTHORIZATION_VERIFY for card tokenization (Apple/Google Pay)
cardIdstringThe card being used
cardholderIdstringThe cardholder who holds the card
amountnumberAmount in dollars. 0.00 for tokenization events
feeAmountnumberNetwork or cross-border fee in dollars. 0.00 for tokenization events
currencystringAuthorization currency (ISO 4217)
merchantNamestringMerchant name from the card network
merchantMccstringMerchant Category Code (ISO 18245). Empty string if not provided by the network
merchantCountrystringTwo-letter country code where the merchant is located. Empty string if not provided
isOneTimeUsebooleanWhether the card is configured for single use
timestampstringISO 8601 timestamp of the authorization request
Fyatu applies a balance gate before calling your endpoint — your endpoint is never called if the gate fails.
  • AUTHORIZATION: program balance must be ≥ amount + feeAmount. On approval, that amount is reserved from your ledger.
  • AUTHORIZATION_VERIFY: program balance must be ≥ $1.00 to confirm the program is funded before a card is tokenized.
Similarly, if the card is FROZEN or TERMINATED, Fyatu declines automatically and does not forward the request to you.

Your Response

Respond with HTTP 200 and a JSON body. The decision field is required for both action types.

Approve

{
  "decision": "APPROVE"
}

Decline

{
  "decision": "DECLINE",
  "reason":   "VELOCITY_EXCEED"
}

Response Fields

FieldTypeRequiredDescription
decisionstringYes"APPROVE" or "DECLINE"
reasonstringNoDecline reason code. Ignored when decision is "APPROVE"

Decline Reason Codes

CodeWhen to use
VELOCITY_EXCEEDSpending limit exceeded
INVALID_MERCHANTMerchant is not permitted for this program
BLK_MRCHMerchant is on your blocked list
TXN_NOT_PERMITThis transaction type is not allowed
SUSPECT_FRAUDTransaction flagged as suspicious
RESTRICTEDCard is suspended or access is restricted
CASH_REQ_EXCEEDCash withdrawal limit exceeded
DO_NOT_HONOURGeneric decline — use when no specific code applies
If you return an unrecognised reason code, Fyatu substitutes DO_NOT_HONOUR.

What Happens After Your Response

Purchase (type: AUTHORIZATION)

Tokenization (type: AUTHORIZATION_VERIFY)


Timeout and Fallback Behaviour

ScenarioFyatu’s action
Card is FROZEN or TERMINATEDAuto-decline — your endpoint is not called
AUTHORIZATION: program balance < amount + feeAmountAuto-decline — your endpoint is not called
AUTHORIZATION_VERIFY: program balance < $1.00Auto-decline — your endpoint is not called
Your endpoint responds {"decision": "APPROVE"} within 1.2 sAction approved
Your endpoint responds {"decision": "DECLINE", ...} within 1.2 sAction declined
No CARD_AUTHORIZATION_VERIFY endpoint registeredAuto-approve (fail-open)
Endpoint does not respond within 1.2 sAuto-approve (fail-open)
Endpoint returns non-2xx HTTP statusAuto-approve (fail-open)
Response body cannot be parsedAuto-approve (fail-open)
Failing open is intentional. An unexpected approval is recoverable — you can investigate after the fact. An unexpected decline silently blocks a legitimate cardholder action and is not recoverable. If you need guaranteed blocking for a card (e.g. a terminated cardholder), use the card lifecycle endpoints (freeze, terminate) — do not rely solely on this webhook.

Example Handler

import json
from flask import Flask, request, jsonify, abort
import hmac, hashlib, time

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_secret_here"

def verify_fyatu_signature(payload_bytes, signature_header, secret):
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    ts = parts.get("t", "")
    received = parts.get("v1", "")
    if abs(time.time() - int(ts)) > 300:
        return False
    signed = f"{ts}.{payload_bytes.decode()}"
    expected = hmac.new(secret.encode(), signed.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received)

@app.route("/fyatu/authorization", methods=["POST"])
def authorize():
    sig = request.headers.get("X-Fyatu-Signature", "")
    if not verify_fyatu_signature(request.data, sig, WEBHOOK_SECRET):
        abort(401)

    event = request.get_json()
    data        = event["data"]
    action_type = data["type"]
    card_id     = data["cardId"]
    amount      = data["amount"]
    fee         = data.get("feeAmount", 0)
    mcc         = data.get("merchantMcc", "")

    if action_type == "AUTHORIZATION_VERIFY":
        return jsonify({"decision": "APPROVE"})

    BLOCKED_MCCS = {"7995", "7994", "7993"}
    if mcc in BLOCKED_MCCS:
        return jsonify({"decision": "DECLINE", "reason": "INVALID_MERCHANT"})

    if exceeds_card_limit(card_id, amount + fee):
        return jsonify({"decision": "DECLINE", "reason": "VELOCITY_EXCEED"})

    return jsonify({"decision": "APPROVE"})

EventWhen it fires
TRANSACTION_AUTHORIZEDAuthorization confirmed by the card network after your APPROVE
TRANSACTION_CLEAREDTransaction fully settled
TRANSACTION_DECLINEDAuthorization declined (by you or by Fyatu)
ACCOUNT_LOW_BALANCEProgram balance dropped below your configured threshold
{
  "event":      "CARD_AUTHORIZATION_VERIFY",
  "eventId":    "evt_01HXYZ987654FEDCBA",
  "businessId": "BUS1A2B3C4D5E6F",
  "timestamp":  "2026-05-27T14:32:00Z",
  "data": {
    "type":            "AUTHORIZATION",
    "cardId":          "crd_01HXYZ5555ABCDEF1111",
    "cardholderId":    "chl_01HXYZ1234ABCDEF5678",
    "amount":          42.50,
    "feeAmount":       1.25,
    "currency":        "USD",
    "merchantName":    "Amazon",
    "merchantMcc":     "5999",
    "merchantCountry": "US",
    "isOneTimeUse":    false,
    "timestamp":       "2026-05-27T14:32:01Z"
  }
}
{
  "decision": "APPROVE"
}

Authorizations

Authorization
string
header
required

API key from the FYATU CaaS portal. Pass as Authorization: Bearer <key>.

Body

application/json
event
string
Example:

"CARD_AUTHORIZATION_VERIFY"

eventId
string
businessId
string
environment
enum<string>
Available options:
LIVE,
SANDBOX
timestamp
string<date-time>
data
object

Response

200 - application/json

Your authorization decision. Return this within 1 second. If your endpoint times out or returns a non-2xx status, Fyatu auto-approves.

decision
enum<string>
required

APPROVE to allow the transaction; DECLINE to block it.

Available options:
APPROVE,
DECLINE
reason
enum<string>

Optional decline reason code. Ignored when decision is APPROVE.

Available options:
VELOCITY_EXCEED,
INVALID_MERCHANT,
BLK_MRCH,
TXN_NOT_PERMIT,
SUSPECT_FRAUD,
RESTRICTED,
CASH_REQ_EXCEED,
DO_NOT_HONOUR