{
 "openapi": "3.1.0",
 "info": {
  "title": "APIcultura API v1",
  "version": "1.0.0-prelaunch",
  "summary": "Gateway de APIs pré-pagas para agentes de IA.",
  "description": "Contrato público (clientes de API) da APIcultura. Dinheiro é inteiro em micro-reais (1 R$ = 1.000.000); campos `*_brl` são strings decimais para exibição. Erros: `{\"error\":\"mensagem\",\"code\":\"CODIGO\"}`.",
  "contact": {
   "name": "APIcultura",
   "url": "https://apicultura.app/"
  }
 },
 "servers": [
  {
   "url": "https://api.apicultura.app",
   "description": "API"
  }
 ],
 "tags": [
  {
   "name": "Chamada paga"
  },
  {
   "name": "Catálogo"
  },
  {
   "name": "Workflows"
  },
  {
   "name": "Saldo"
  },
  {
   "name": "Saúde"
  }
 ],
 "externalDocs": {
  "description": "Documentação para agentes",
  "url": "https://apicultura.app/agents/"
 },
 "paths": {
  "/v1/health": {
   "get": {
    "tags": [
     "Saúde"
    ],
    "operationId": "getHealth",
    "summary": "Estado do serviço",
    "security": [],
    "responses": {
     "200": {
      "description": "Serviço no ar.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalog/tools": {
   "get": {
    "tags": [
     "Catálogo"
    ],
    "operationId": "listTools",
    "summary": "Lista as ferramentas do catálogo público",
    "security": [],
    "description": "Sem login; cache de 60 s.",
    "responses": {
     "200": {
      "description": "Lista de ferramentas.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Tool"
           }
          },
          "meta": {
           "type": "object",
           "properties": {
            "total": {
             "type": "integer"
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalog/tools/{slug}": {
   "get": {
    "tags": [
     "Catálogo"
    ],
    "operationId": "getTool",
    "summary": "Detalhe de uma ferramenta, com endpoints",
    "security": [],
    "parameters": [
     {
      "name": "slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "serp"
     }
    ],
    "responses": {
     "200": {
      "description": "Ferramenta e endpoints.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ToolDetail"
        }
       }
      }
     },
     "404": {
      "description": "Ferramenta inexistente.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalog/search": {
   "get": {
    "tags": [
     "Catálogo"
    ],
    "operationId": "searchCatalog",
    "summary": "Busca de endpoints em linguagem natural (português)",
    "security": [],
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "maxLength": 200
      },
      "example": "quero buscar no google"
     }
    ],
    "responses": {
     "200": {
      "description": "Endpoints ordenados por relevância.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Endpoint"
           }
          },
          "meta": {
           "type": "object"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalog": {
   "get": {
    "tags": [
     "Catálogo"
    ],
    "operationId": "listEndpoints",
    "summary": "Lista plana de endpoints",
    "security": [],
    "responses": {
     "200": {
      "description": "Endpoints.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Endpoint"
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/call/{endpoint_slug}": {
   "post": {
    "tags": [
     "Chamada paga"
    ],
    "operationId": "callEndpoint",
    "summary": "Executa um endpoint do catálogo (cobrado)",
    "description": "Fluxo: valida a entrada, aplica limite de taxa, reserva o preço do catálogo, chama o serviço e então cobra (sucesso) ou devolve a reserva (falha). O cliente nunca informa preço. Exige escopo `call` na chave.",
    "security": [
     {
      "bearerAuth": []
     }
    ],
    "parameters": [
     {
      "name": "endpoint_slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "serp-search"
     },
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Obrigatório. Mesma chave + mesmo corpo = mesma resposta (cabeçalho `Idempotent-Replayed: true`); corpo diferente = 422. Validade de 24 h."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": true,
        "description": "Objeto conforme o `input_schema` do endpoint (veja o catálogo). Máximo 256 KB."
       },
       "example": {
        "q": "melhor cafe de sao paulo",
        "limit": 5
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Sucesso.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CallResult"
        }
       }
      }
     },
     "400": {
      "description": "`INVALID_INPUT` ou `IDEMPOTENCY_KEY_REQUIRED`. Nada é cobrado.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Chave ausente, inválida ou revogada (`INVALID_API_KEY`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "402": {
      "description": "`INSUFFICIENT_BALANCE`: saldo insuficiente.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "`FORBIDDEN` (sem escopo `call`) ou `KEY_SPEND_LIMIT` (teto diário/mensal da chave).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "`ENDPOINT_NOT_FOUND`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "`IDEMPOTENCY_IN_PROGRESS`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "413": {
      "description": "`BODY_TOO_LARGE`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "`REQUEST_REJECTED` ou `IDEMPOTENCY_CONFLICT`. Não cobrado.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Limite de taxa excedido (`RATE_LIMITED`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "schema": {
         "type": "integer"
        },
        "description": "Segundos até poder tentar de novo."
       }
      }
     },
     "502": {
      "description": "`SERVICE_UNAVAILABLE`. Não cobrado; reserva devolvida.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/balance": {
   "get": {
    "tags": [
     "Saldo"
    ],
    "operationId": "getBalance",
    "summary": "Saldo da conta",
    "description": "Escopo `balance` na chave.",
    "security": [
     {
      "bearerAuth": []
     }
    ],
    "responses": {
     "200": {
      "description": "Saldo.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Balance"
        }
       }
      }
     },
     "401": {
      "description": "Chave ausente, inválida ou revogada (`INVALID_API_KEY`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Limite de taxa excedido (`RATE_LIMITED`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "schema": {
         "type": "integer"
        },
        "description": "Segundos até poder tentar de novo."
       }
      }
     }
    }
   }
  },
  "/v1/transactions": {
   "get": {
    "tags": [
     "Saldo"
    ],
    "operationId": "listTransactions",
    "summary": "Extrato do próprio saldo",
    "description": "Escopo `balance` na chave.",
    "security": [
     {
      "bearerAuth": []
     }
    ],
    "parameters": [
     {
      "name": "page",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "default": 1
      }
     },
     {
      "name": "per_page",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "default": 20
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Transações.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Transaction"
           }
          },
          "meta": {
           "type": "object",
           "properties": {
            "page": {
             "type": "integer"
            },
            "per_page": {
             "type": "integer"
            },
            "total": {
             "type": "integer"
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Chave ausente, inválida ou revogada (`INVALID_API_KEY`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Limite de taxa excedido (`RATE_LIMITED`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "schema": {
         "type": "integer"
        },
        "description": "Segundos até poder tentar de novo."
       }
      }
     }
    }
   }
  },
  "/v1/workflows": {
   "get": {
    "tags": [
     "Workflows"
    ],
    "operationId": "listWorkflows",
    "summary": "Lista os workflows executáveis",
    "security": [],
    "description": "Cada workflow também é a ferramenta MCP `workflow_<slug>`.",
    "responses": {
     "200": {
      "description": "Workflows e seus argumentos.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/v1/workflows/{slug}/run": {
   "post": {
    "tags": [
     "Workflows"
    ],
    "operationId": "runWorkflow",
    "summary": "Devolve o plano do workflow (grátis)",
    "description": "Não executa nem cobra: devolve instruções passo a passo e a sequência de chamadas a ferramentas reais do catálogo, com parâmetros preenchidos pelos argumentos. Cada chamada de ferramenta é cobrada normalmente em `POST /v1/call/{endpoint_slug}`.",
    "security": [
     {
      "bearerAuth": []
     }
    ],
    "parameters": [
     {
      "name": "slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "prospeccao-b2b"
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "argumentos": {
          "type": "object",
          "additionalProperties": true
         }
        }
       },
       "example": {
        "argumentos": {
         "nicho": "clínicas odontológicas",
         "cidade": "Campinas/SP"
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Plano estruturado (passos, chamadas, custo estimado).",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "`INVALID_INPUT`: argumento ausente ou inválido.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Chave ausente, inválida ou revogada (`INVALID_API_KEY`).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "`NOT_FOUND`: workflow inexistente.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearerAuth": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "apk_live_<id>_<segredo>",
    "description": "Chave de API. Também aceita no cabeçalho `X-API-Key`."
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "required": [
     "error",
     "code"
    ],
    "properties": {
     "error": {
      "type": "string"
     },
     "code": {
      "type": "string",
      "examples": [
       "INSUFFICIENT_BALANCE"
      ]
     }
    }
   },
   "Tool": {
    "type": "object",
    "properties": {
     "slug": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "icon": {
      "type": "string"
     },
     "category": {
      "type": "string"
     },
     "endpoints_count": {
      "type": "integer"
     },
     "min_price_micro": {
      "type": "integer"
     },
     "min_price_brl": {
      "type": "string",
      "examples": [
       "0.03"
      ]
     }
    }
   },
   "Endpoint": {
    "type": "object",
    "properties": {
     "slug": {
      "type": "string"
     },
     "title": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "method": {
      "type": "string"
     },
     "price_micro": {
      "type": "integer"
     },
     "price_brl": {
      "type": "string"
     },
     "input_schema": {
      "type": "object"
     },
     "example_request": {
      "type": "object"
     },
     "example_curl": {
      "type": "string"
     },
     "tool": {
      "type": "string"
     }
    }
   },
   "ToolDetail": {
    "allOf": [
     {
      "$ref": "#/components/schemas/Tool"
     },
     {
      "type": "object",
      "properties": {
       "endpoints": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/Endpoint"
        }
       }
      }
     }
    ]
   },
   "CallResult": {
    "type": "object",
    "properties": {
     "data": {
      "type": "object",
      "additionalProperties": true
     },
     "meta": {
      "type": "object",
      "properties": {
       "request_id": {
        "type": "string",
        "format": "uuid"
       },
       "cost_micro": {
        "type": "integer"
       },
       "cost_brl": {
        "type": "string"
       },
       "cached": {
        "type": "boolean"
       }
      }
     }
    }
   },
   "Balance": {
    "type": "object",
    "properties": {
     "balance_micro": {
      "type": "integer"
     },
     "hold_micro": {
      "type": "integer",
      "description": "Reservado por chamadas em andamento."
     },
     "currency": {
      "type": "string",
      "const": "BRL"
     },
     "low_balance": {
      "type": "boolean"
     }
    }
   },
   "Transaction": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "type": {
      "type": "string",
      "enum": [
       "credit",
       "hold",
       "capture",
       "release",
       "adjust",
       "refund"
      ]
     },
     "kind": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "amount_micro": {
      "type": "integer"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   }
  }
 }
}