> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fyatu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CARD_AUTHORIZATION_VERIFY

> Synchronous authorization request sent to your webhook for every JIT card event. Your response controls whether the action is approved or declined.

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.

<Warning>
  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.
</Warning>

***

## Event Type

```
CARD_AUTHORIZATION_VERIFY
```

***

## When It Fires

This event fires for two distinct actions, distinguished by the `type` field in `data`:

| `data.type`            | What it means                                                               | Fyatu balance gate                                                                                                         |
| ---------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `AUTHORIZATION`        | A 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_VERIFY` | A 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

```json theme={null}
{
  "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

| Field             | Type    | Description                                                                                     |
| ----------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `type`            | string  | `AUTHORIZATION` for a purchase, `AUTHORIZATION_VERIFY` for card tokenization (Apple/Google Pay) |
| `cardId`          | string  | The card being used                                                                             |
| `cardholderId`    | string  | The cardholder who holds the card                                                               |
| `amount`          | number  | Amount in dollars. `0.00` for tokenization events                                               |
| `feeAmount`       | number  | Network or cross-border fee in dollars. `0.00` for tokenization events                          |
| `currency`        | string  | Authorization currency (ISO 4217)                                                               |
| `merchantName`    | string  | Merchant name from the card network                                                             |
| `merchantMcc`     | string  | Merchant Category Code (ISO 18245). Empty string if not provided by the network                 |
| `merchantCountry` | string  | Two-letter country code where the merchant is located. Empty string if not provided             |
| `isOneTimeUse`    | boolean | Whether the card is configured for single use                                                   |
| `timestamp`       | string  | ISO 8601 timestamp of the authorization request                                                 |

<Note>
  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.
</Note>

***

## Your Response

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

### Approve

```json theme={null}
{
  "decision": "APPROVE"
}
```

### Decline

```json theme={null}
{
  "decision": "DECLINE",
  "reason":   "VELOCITY_EXCEED"
}
```

### Response Fields

| Field      | Type   | Required | Description                                                 |
| ---------- | ------ | -------- | ----------------------------------------------------------- |
| `decision` | string | Yes      | `"APPROVE"` or `"DECLINE"`                                  |
| `reason`   | string | No       | Decline reason code. Ignored when `decision` is `"APPROVE"` |

### Decline Reason Codes

| Code               | When to use                                         |
| ------------------ | --------------------------------------------------- |
| `VELOCITY_EXCEED`  | Spending limit exceeded                             |
| `INVALID_MERCHANT` | Merchant is not permitted for this program          |
| `BLK_MRCH`         | Merchant is on your blocked list                    |
| `TXN_NOT_PERMIT`   | This transaction type is not allowed                |
| `SUSPECT_FRAUD`    | Transaction flagged as suspicious                   |
| `RESTRICTED`       | Card is suspended or access is restricted           |
| `CASH_REQ_EXCEED`  | Cash withdrawal limit exceeded                      |
| `DO_NOT_HONOUR`    | Generic 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)

```mermaid theme={null}
flowchart TD
    A([Card network sends authorization]) --> B{Card ACTIVE?}
    B -->|FROZEN or TERMINATED| C([DECLINE → card network])
    B -->|ACTIVE| D{Balance ≥ amount + fee?}
    D -->|Insufficient| E([DECLINE → card network])
    D -->|Sufficient| F[Forward to your server\nCARD_AUTHORIZATION_VERIFY]
    F -->|APPROVE| G([APPROVE → card network])
    F -->|DECLINE| H([DECLINE → card network])
    G --> I[TRANSACTION_AUTHORIZED\nfunds reserved from program ledger]
    I --> J[...]
    J --> K([TRANSACTION_CLEARED\ntransaction settled])

    style C fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style E fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style H fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style G fill:#dcfce7,stroke:#22c55e,color:#14532d
    style K fill:#dcfce7,stroke:#22c55e,color:#14532d
```

### Tokenization (type: AUTHORIZATION\_VERIFY)

```mermaid theme={null}
flowchart TD
    A([Cardholder adds card to Apple / Google Pay]) --> B{Card ACTIVE?}
    B -->|FROZEN or TERMINATED| C([DECLINE → wallet provider])
    B -->|ACTIVE| D{Balance ≥ $1.00?}
    D -->|Insufficient| E([DECLINE → wallet provider])
    D -->|Sufficient| F[Forward to your server\nCARD_AUTHORIZATION_VERIFY]
    F -->|APPROVE| G([Card added to wallet])
    F -->|DECLINE| H([Card rejected by wallet provider])

    style C fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style E fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style H fill:#fee2e2,stroke:#ef4444,color:#7f1d1d
    style G fill:#dcfce7,stroke:#22c55e,color:#14532d
```

***

## Timeout and Fallback Behaviour

| Scenario                                                           | Fyatu's action                             |
| ------------------------------------------------------------------ | ------------------------------------------ |
| Card is `FROZEN` or `TERMINATED`                                   | Auto-decline — your endpoint is not called |
| `AUTHORIZATION`: program balance \< `amount + feeAmount`           | Auto-decline — your endpoint is not called |
| `AUTHORIZATION_VERIFY`: program balance \< \$1.00                  | Auto-decline — your endpoint is not called |
| Your endpoint responds `{"decision": "APPROVE"}` within 1.2 s      | Action approved                            |
| Your endpoint responds `{"decision": "DECLINE", ...}` within 1.2 s | Action declined                            |
| No `CARD_AUTHORIZATION_VERIFY` endpoint registered                 | Auto-approve (fail-open)                   |
| Endpoint does not respond within 1.2 s                             | Auto-approve (fail-open)                   |
| Endpoint returns non-2xx HTTP status                               | Auto-approve (fail-open)                   |
| Response body cannot be parsed                                     | Auto-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

<CodeGroup>
  ```python Python theme={null}
  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"})
  ```

  ```typescript Node.js theme={null}
  import express from 'express'
  import crypto from 'crypto'

  const app = express()
  app.use(express.raw({ type: 'application/json' }))

  const WEBHOOK_SECRET = process.env.FYATU_WEBHOOK_SECRET!

  function verifySignature(payload: Buffer, header: string): boolean {
    const parts = Object.fromEntries(header.split(',').map(p => p.split('=')))
    const ts = parts['t']
    const received = parts['v1']
    if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
    const signed = `${ts}.${payload.toString()}`
    const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(signed).digest('hex')
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))
  }

  app.post('/fyatu/authorization', (req, res) => {
    const sig = req.headers['x-fyatu-signature'] as string
    if (!verifySignature(req.body, sig)) return res.status(401).send()

    const event = JSON.parse(req.body.toString())
    const { type, cardId, amount, feeAmount = 0, merchantMcc } = event.data

    if (type === 'AUTHORIZATION_VERIFY') {
      return res.json({ decision: 'APPROVE' })
    }

    const BLOCKED_MCCS = new Set(['7995', '7994', '7993'])
    if (BLOCKED_MCCS.has(merchantMcc)) {
      return res.json({ decision: 'DECLINE', reason: 'INVALID_MERCHANT' })
    }

    if (exceedsCardLimit(cardId, amount + feeAmount)) {
      return res.json({ decision: 'DECLINE', reason: 'VELOCITY_EXCEED' })
    }

    return res.json({ decision: 'APPROVE' })
  })
  ```
</CodeGroup>

***

## Related Events

| Event                                                                     | When it fires                                                  |
| ------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [`TRANSACTION_AUTHORIZED`](/v3.20/webhooks/events/transaction-authorized) | Authorization confirmed by the card network after your APPROVE |
| [`TRANSACTION_CLEARED`](/v3.20/webhooks/events/transaction-cleared)       | Transaction fully settled                                      |
| [`TRANSACTION_DECLINED`](/v3.20/webhooks/events/transaction-declined)     | Authorization declined (by you or by Fyatu)                    |
| [`ACCOUNT_LOW_BALANCE`](/v3.20/webhooks/events/account-low-balance)       | Program balance dropped below your configured threshold        |

<RequestExample>
  ```json Purchase (AUTHORIZATION) theme={null}
  {
    "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"
    }
  }
  ```

  ```json Tokenization (AUTHORIZATION_VERIFY) theme={null}
  {
    "event":      "CARD_AUTHORIZATION_VERIFY",
    "eventId":    "evt_01HXYZ987654FEDCBB",
    "businessId": "BUS1A2B3C4D5E6F",
    "timestamp":  "2026-05-27T14:35:00Z",
    "data": {
      "type":            "AUTHORIZATION_VERIFY",
      "cardId":          "crd_01HXYZ5555ABCDEF1111",
      "cardholderId":    "chl_01HXYZ1234ABCDEF5678",
      "amount":          0.00,
      "feeAmount":       0.00,
      "currency":        "USD",
      "merchantName":    "Apple Pay",
      "merchantMcc":     "",
      "merchantCountry": "US",
      "isOneTimeUse":    false,
      "timestamp":       "2026-05-27T14:35:01Z"
    }
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 — Approve theme={null}
  {
    "decision": "APPROVE"
  }
  ```

  ```json 200 — Decline theme={null}
  {
    "decision": "DECLINE",
    "reason":   "VELOCITY_EXCEED"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml v3.20/openapi.json webhook CARD_AUTHORIZATION_VERIFY
openapi: 3.1.0
info:
  title: FYATU CaaS API v3.20
  description: >-
    FYATU Cards-as-a-Service API â€” API key authentication, Cardholder
    lifecycle, Card issuance, Transactions, Webhooks, and Programs.
  version: 3.20.0
  contact:
    name: FYATU Support
    url: https://fyatu.com
    email: support@fyatu.com
servers:
  - url: https://api.fyatu.com/api/v3.20
    description: >-
      FYATU CaaS API â€” the environment (LIVE or SANDBOX) is determined by the
      API key, not the URL
security:
  - BearerAuth: []
tags:
  - name: Meta
    description: Liveness, account info, and supported event types
  - name: Account
    description: Account-level balance and funding status
  - name: Programs
    description: Read card program configuration
  - name: Cardholders
    description: Create and manage cardholder profiles
  - name: Cards
    description: Issue, fund, freeze, and terminate virtual cards
  - name: Transactions
    description: Read-only card transaction history
  - name: Webhooks
    description: Manage webhook endpoints for real-time event delivery
  - name: Products
    description: Read card product configurations
paths: {}
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        API key from the FYATU CaaS portal. Pass as `Authorization: Bearer
        <key>`.

````