{
  "openapi": "3.1.0",
  "info": {
    "title": "ZentPay Hosted API",
    "version": "1.2.0",
    "description": "Hosted ZentPay payment, authorization, order, delivery, and developer integration API."
  },
  "servers": [
    {
      "url": "https://api.zentpay.app",
      "description": "Production Base Sepolia hosted API"
    }
  ],
  "security": [],
  "paths": {
    "/health": {
      "get": {
        "summary": "Service health",
        "responses": {
          "200": {
            "description": "Service status"
          }
        }
      }
    },
    "/api/catalog": {
      "get": {
        "summary": "List public apps and products",
        "responses": {
          "200": {
            "description": "Public app catalog"
          }
        }
      }
    },
    "/api/hosted/{appSlug}": {
      "get": {
        "summary": "Read hosted entry config",
        "parameters": [
          {
            "name": "appSlug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "description": "Hosted app config" },
          "404": { "description": "Hosted app not found" }
        }
      }
    },
    "/api/authorizations/budget-spender": {
      "get": {
        "summary": "List BudgetSpender authorizations for a wallet",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" }
          },
          {
            "name": "spender",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" }
          }
        ],
        "responses": {
          "200": {
            "description": "Authorization history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["authorizations"],
                  "properties": {
                    "authorizations": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Authorization" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/authorizations/return-code": {
      "post": {
        "summary": "Create a short-lived hosted authorization return code",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["appSlug", "owner", "spender", "authorizationId", "returnUrl"],
                "properties": {
                  "appSlug": { "type": "string" },
                  "owner": { "type": "string" },
                  "spender": { "type": "string" },
                  "authorizationId": { "type": "string" },
                  "returnUrl": { "type": "string", "format": "uri" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Return code and redirect URL" },
          "400": { "description": "Missing fields or invalid return URL" },
          "404": { "description": "Hosted app not found" },
          "403": { "description": "Active authorization not found" }
        }
      }
    },
    "/api/authorizations/summary": {
      "get": {
        "summary": "Exchange a hosted authorization return code for a safe summary",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "description": "Authorization summary" },
          "401": { "description": "Invalid or expired code" }
        }
      }
    },
    "/api/pay/{appSlug}/{productSlug}": {
      "post": {
        "summary": "Pay a direct product route with an existing BudgetSpender authorization",
        "parameters": [
          {
            "name": "appSlug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "productSlug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "x-wallet-address",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "x-zentpay-budget-spender",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["authorizationCode", "idempotencyKey"],
                "properties": {
                  "authorizationCode": {
                    "type": "string",
                    "description": "Short-lived app/origin/wallet/spender-bound code returned by /api/authorizations/summary."
                  },
                  "idempotencyKey": { "type": "string" },
                  "developerUserId": { "type": "string" },
                  "orderId": { "type": "string" },
                  "source": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delivery created and fulfillment can proceed through webhook or delivery lookup",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentResult" }
              }
            }
          },
          "400": { "description": "Invalid wallet, recipient, or request configuration" },
          "402": { "description": "Budget authorization required or insufficient" },
          "503": { "description": "Ledger or payment service dependency unavailable" }
        }
      }
    },
    "/api/orders": {
      "post": {
        "summary": "Create a server-side order",
        "security": [{ "secretApiKey": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["productId", "idempotencyKey"],
                "properties": {
                  "productId": { "type": "string" },
                  "developerUserId": { "type": "string" },
                  "idempotencyKey": { "type": "string" },
                  "metadata": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Order created" },
          "401": { "description": "Secret API key required" }
        }
      }
    },
    "/api/orders/{orderId}": {
      "get": {
        "summary": "Read an order",
        "security": [{ "secretApiKey": [] }],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "description": "Order details" },
          "401": { "description": "Secret API key required" },
          "404": { "description": "Order not found" }
        }
      }
    },
    "/api/deliveries/{deliveryId}": {
      "get": {
        "summary": "Reconcile a delivery",
        "security": [{ "secretApiKey": [] }],
        "parameters": [
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Delivery" }
              }
            }
          },
          "401": { "description": "Secret API key required" },
          "403": { "description": "API key scope does not allow delivery lookup" },
          "404": { "description": "Delivery not found" }
        }
      }
    },
    "/api/receipts/{txHash}": {
      "get": {
        "summary": "Read a receipt by settlement transaction hash",
        "security": [{ "secretApiKey": [] }],
        "parameters": [
          {
            "name": "txHash",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "description": "Receipt delivery details" },
          "401": { "description": "Secret API key required" },
          "404": { "description": "Receipt not found" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "secretApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use a server-side ZentPay secret API key such as zpk_test_..."
      }
    },
    "schemas": {
      "Authorization": {
        "type": "object",
        "required": ["authorizationId", "ownerWallet", "spender", "allowance", "spent", "remaining", "status"],
        "properties": {
          "authorizationId": { "type": "string" },
          "ownerWallet": { "type": "string" },
          "spender": { "type": "string" },
          "token": { "type": "string" },
          "allowance": { "type": "string", "description": "Atomic USDC allowance." },
          "spent": { "type": "string", "description": "Atomic USDC spent through the ZentPay ledger." },
          "remaining": { "type": "string", "description": "Atomic USDC remaining budget. Use this for UI." },
          "status": { "type": "string", "enum": ["active", "exhausted", "revoked"] },
          "expiresAt": { "type": ["string", "null"], "format": "date-time" },
          "updatedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "PaymentResult": {
        "type": "object",
        "required": ["ok", "success", "deliveryId", "idempotencyKey", "status", "fulfilled", "mode", "settlementStatus", "traceId", "chargeId"],
        "properties": {
          "ok": { "type": "boolean" },
          "success": { "type": "boolean" },
          "deliveryId": { "type": "string" },
          "idempotencyKey": { "type": "string" },
          "status": { "type": "string" },
          "fulfilled": { "type": "boolean" },
          "mode": { "type": "string", "description": "Current hosted payment mode, for example budget-spender-reserved." },
          "settlementStatus": { "type": "string" },
          "traceId": { "type": "string" },
          "itemId": { "type": ["string", "null"] },
          "walletAddress": { "type": ["string", "null"] },
          "txHash": { "type": ["string", "null"] },
          "chargeId": { "type": "string" },
          "remaining": { "type": ["string", "null"] },
          "reward": { "type": ["object", "null"], "additionalProperties": true },
          "webhookResults": {
            "type": ["array", "null"],
            "items": { "type": "object", "additionalProperties": true },
            "description": "Best-effort webhook scheduling results. Fulfillment must still be confirmed by signed webhook or trusted delivery lookup."
          }
        }
      },
      "Delivery": {
        "type": "object",
        "required": ["deliveryId", "idempotencyKey", "status"],
        "properties": {
          "deliveryId": { "type": "string" },
          "chargeId": { "type": ["string", "null"] },
          "idempotencyKey": { "type": "string" },
          "appId": { "type": ["string", "null"] },
          "productId": { "type": ["string", "null"] },
          "orderId": { "type": ["string", "null"] },
          "developerUserId": { "type": ["string", "null"] },
          "walletAddress": { "type": ["string", "null"] },
          "amount": { "type": ["string", "null"] },
          "paymentMode": { "type": ["string", "null"] },
          "status": { "type": "string" },
          "fulfilled": { "type": "boolean" },
          "settlementStatus": { "type": ["string", "null"] },
          "settlementTxHash": { "type": ["string", "null"] },
          "deliveredAt": { "type": ["string", "null"], "format": "date-time" }
        }
      }
    }
  }
}
