{
  "openapi": "3.1.0",
  "info": {
    "title": "VELTIS API",
    "version": "1.0.0",
    "description": "API server-to-server da VELTIS para cobranças PIX, transferências, saldo e conciliação. Valores monetários são inteiros em centavos."
  },
  "servers": [
    { "url": "https://api.veltispay.com/v1", "description": "Produção" }
  ],
  "security": [
    { "VeltisKey": [], "VeltisSecret": [] }
  ],
  "components": {
    "securitySchemes": {
      "VeltisKey": { "type": "apiKey", "in": "header", "name": "X-Veltis-Key" },
      "VeltisSecret": { "type": "apiKey", "in": "header", "name": "X-Veltis-Secret" }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["success", "error"],
        "properties": {
          "success": { "type": "boolean", "const": false },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" }
            }
          }
        }
      },
      "Charge": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "const": "charge" },
          "amount": { "type": "integer" },
          "fee": { "type": "integer" },
          "net_amount": { "type": "integer" },
          "currency": { "type": "string", "example": "BRL" },
          "status": { "type": "string" },
          "description": { "type": ["string", "null"] },
          "external_reference": { "type": ["string", "null"] },
          "customer": { "type": ["object", "null"] },
          "return_url": { "type": ["string", "null"] },
          "metadata": { "type": ["object", "null"] },
          "pix": {
            "type": "object",
            "properties": {
              "copy_paste": { "type": "string" },
              "qr_code_payload": { "type": "string" },
              "qr_code_image": { "type": ["string", "null"] },
              "expires_at": { "type": ["string", "null"] }
            }
          },
          "checkout_url": { "type": "string" },
          "paid_at": { "type": ["string", "null"] },
          "created_at": { "type": "string" }
        }
      },
      "Payout": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "const": "payout" },
          "amount": { "type": "integer" },
          "recipient_amount": { "type": "integer" },
          "fee": { "type": "integer" },
          "total_debit": { "type": "integer" },
          "status": { "type": "string" },
          "pix_key": { "type": "string" },
          "pix_key_type": { "type": "string", "enum": ["cpf", "cnpj", "email", "phone", "evp"] },
          "recipient_name": { "type": "string" },
          "recipient_document": { "type": "string" },
          "external_reference": { "type": ["string", "null"] },
          "paid_at": { "type": ["string", "null"] },
          "failure_reason": { "type": ["string", "null"] },
          "created_at": { "type": "string" }
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": { "type": "string", "maxLength": 191 },
        "description": "Identificador único da intenção financeira. Reutilize a mesma chave após timeout com o mesmo payload."
      }
    }
  },
  "paths": {
    "/fees/pix-quote": {
      "get": {
        "summary": "Cotar cobrança PIX",
        "parameters": [{ "name": "amount", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 100 } }],
        "responses": { "200": { "description": "Cotação calculada" }, "4XX": { "description": "Erro", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }
      }
    },
    "/charges": {
      "get": { "summary": "Listar cobranças", "responses": { "200": { "description": "Cobranças recentes" } } },
      "post": {
        "summary": "Criar cobrança PIX",
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["amount"],
                "properties": {
                  "amount": { "type": "integer", "minimum": 100 },
                  "description": { "type": "string" },
                  "external_reference": { "type": "string" },
                  "return_url": { "type": "string", "format": "uri" },
                  "customer": { "type": "object" },
                  "metadata": { "type": "object" }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Cobrança criada", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "$ref": "#/components/schemas/Charge" } } } } } } }
      }
    },
    "/charges/{id}": {
      "get": {
        "summary": "Consultar cobrança",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Cobrança" }, "404": { "description": "Não encontrada" } }
      }
    },
    "/charges/{id}/sync": {
      "post": {
        "summary": "Sincronizar cobrança",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Cobrança sincronizada" }, "409": { "description": "Cobrança ainda sem ID no serviço de liquidação" } }
      }
    },
    "/fees/payout-quote": {
      "get": {
        "summary": "Cotar transferência PIX",
        "parameters": [{ "name": "amount", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 100 } }],
        "responses": { "200": { "description": "Cotação calculada" } }
      }
    },
    "/payouts": {
      "get": { "summary": "Listar transferências", "responses": { "200": { "description": "Transferências recentes" } } },
      "post": {
        "summary": "Criar transferência PIX",
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["amount", "recipient_name", "recipient_document", "pix_key_type", "pix_key"],
                "properties": {
                  "amount": { "type": "integer", "minimum": 100 },
                  "recipient_name": { "type": "string" },
                  "recipient_document": { "type": "string" },
                  "pix_key_type": { "type": "string", "enum": ["cpf", "cnpj", "email", "phone", "evp"] },
                  "pix_key": { "type": "string" },
                  "description": { "type": "string" },
                  "external_reference": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Transferência criada", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "$ref": "#/components/schemas/Payout" } } } } } }, "409": { "description": "Conflito ou saldo insuficiente" } }
      }
    },
    "/payouts/{id}": {
      "get": {
        "summary": "Consultar transferência",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Transferência" }, "404": { "description": "Não encontrada" } }
      }
    },
    "/balance": {
      "get": { "summary": "Consultar saldo", "responses": { "200": { "description": "Saldo disponível e reservado" } } }
    },
    "/ledger": {
      "get": {
        "summary": "Consultar extrato",
        "parameters": [{ "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 100 } }],
        "responses": { "200": { "description": "Lançamentos recentes" } }
      }
    }
  }
}
