{
  "openapi": "3.1.0",
  "info": {
    "title": "Elo API",
    "version": "1.0.0",
    "description": "API REST do Elo (CRM comercial multiunidade da FoxGrid) para ERPs e integradores. Toda rota (exceto GET /units) exige a unidade (?unitId= ou body.unitId) e só devolve dados dela. Uma chave pode ser restrita a algumas unidades (403 fora delas) e ter validade (vencida = 401). Auth: Authorization: Bearer ek_live_… (chaves tk_live_ da sprint 1 seguem aceitas). Limite: 120 req/min por chave. Idempotency-Key opcional em POST/PATCH (24 h). Entrada de leads (Meta/Google/site): rotas /api/webhooks/leads/… — sem Bearer, token por entrada (Config → Origens). Detalhes e webhooks: docs/API.md."
  },
  "servers": [{ "url": "https://elo.foxgrid.com.br/api/v1" }],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "ek_live_<12 hex>_<32 base64url>" },
      "inboxToken": { "type": "apiKey", "in": "header", "name": "x-elo-token", "description": "Token da entrada de leads (criado em Config → Origens; mostrado uma vez). Alternativa: ?token=. Só nas rotas /api/webhooks/leads/… — as variantes google e meta não usam header: validam pelo google_key do payload e pela assinatura X-Hub-Signature-256, respectivamente." }
    },
    "parameters": {
      "unitId": { "name": "unitId", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Unidade da conta da chave. Obrigatória em toda rota (exceto GET /units)." },
      "cursor": { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "nextCursor da página anterior." },
      "limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
      "id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
      "idempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string", "maxLength": 200 }, "description": "Mesma chave (por chave de API) devolve a mesma resposta por 24 h (header Idempotent-Replayed: true)." },
      "inboxId": { "name": "inboxId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Id da entrada de leads (Config → Origens)." }
    },
    "schemas": {
      "UnitRef": { "type": "object", "required": ["id", "name", "shortName"], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "shortName": { "type": "string" } } },
      "Unit": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "shortName": { "type": "string" },
          "color": { "type": "string", "description": "hex" },
          "status": { "type": "string", "enum": ["ACTIVE", "ARCHIVED"] },
          "sortOrder": { "type": "integer" },
          "ramalUnitId": { "type": ["string", "null"], "description": "Unidade correspondente no Ramal (mapa 1:1), quando configurado." },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string", "enum": ["UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "VALIDATION", "UNIT_REQUIRED", "RATE_LIMITED", "CONFLICT", "INTERNAL"] },
              "message": { "type": "string" },
              "details": {}
            }
          }
        }
      },
      "Ramal": {
        "type": "object",
        "description": "Vínculos opcionais com o Ramal (INTEGRATION.md §2).",
        "properties": {
          "contactId": { "type": ["string", "null"] },
          "conversationId": { "type": ["string", "null"] },
          "dealId": { "type": ["string", "null"], "description": "Único por conta (409 CONFLICT se já vinculado)." },
          "unitId": { "type": ["string", "null"] }
        }
      },
      "Deal": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "unitId": { "type": "string" },
          "pipelineId": { "type": "string" },
          "stageId": { "type": "string" },
          "stageName": { "type": "string" },
          "title": { "type": "string" },
          "valueMinor": { "type": "integer", "description": "Menor unidade da moeda da conta (centavos BRL / guaranis PYG)." },
          "valueFormatted": { "type": "string" },
          "currency": { "type": "string", "enum": ["BRL", "PYG"] },
          "status": { "type": "string", "enum": ["OPEN", "WON", "LOST"], "description": "Deriva do estágio." },
          "lostReason": { "type": ["string", "null"] },
          "source": { "type": "string", "enum": ["MANUAL", "RAMAL", "IMPORT", "FORM", "API"], "description": "COMO o registro entrou no sistema." },
          "channel": { "type": ["string", "null"], "enum": ["META", "GOOGLE", "ORGANICO", "INDICACAO", "OUTRO", null], "description": "Origem de marketing (de onde o lead veio) — não confundir com source." },
          "campaign": { "type": ["string", "null"] },
          "ad": { "type": ["string", "null"] },
          "ownerMembershipId": { "type": "string" },
          "contactIds": { "type": "array", "items": { "type": "string" } },
          "nextActivityAt": { "type": ["string", "null"], "format": "date-time" },
          "ramalContactId": { "type": ["string", "null"] },
          "ramalConversationId": { "type": ["string", "null"] },
          "ramalDealId": { "type": ["string", "null"] },
          "ramalUnitId": { "type": ["string", "null"] },
          "wonAt": { "type": ["string", "null"], "format": "date-time" },
          "lostAt": { "type": ["string", "null"], "format": "date-time" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "DealProductInput": {
        "type": "object",
        "properties": {
          "productId": { "type": ["string", "null"], "description": "Produto do cadastro — copia nome e preço (snapshot)." },
          "name": { "type": "string", "maxLength": 140 },
          "priceMinor": { "type": "integer", "minimum": 0 },
          "qty": { "type": "integer", "minimum": 1, "default": 1 }
        }
      },
      "DealCreate": {
        "type": "object",
        "required": ["unitId", "title"],
        "properties": {
          "unitId": { "type": "string" },
          "title": { "type": "string", "maxLength": 140 },
          "valueMinor": { "type": "integer", "minimum": 0, "maximum": 2147483647 },
          "pipelineId": { "type": ["string", "null"], "description": "Funil global ou da unidade. Padrão: funil da unidade, senão o padrão da conta." },
          "stageId": { "type": ["string", "null"], "description": "Padrão: 1º estágio aberto do funil." },
          "ownerMembershipId": { "type": ["string", "null"], "description": "Precisa alcançar a unidade. Padrão: quem criou a chave." },
          "contactIds": { "type": "array", "items": { "type": "string" }, "maxItems": 20 },
          "contact": {
            "type": "object",
            "description": "Cria/unifica pelo telefone antes de criar o negócio; vira o contato principal.",
            "properties": { "phone": { "type": ["string", "null"], "description": "DDI+DDD+número, só dígitos" }, "name": { "type": ["string", "null"], "maxLength": 140 } }
          },
          "organizationId": { "type": ["string", "null"] },
          "products": { "type": "array", "items": { "$ref": "#/components/schemas/DealProductInput" }, "maxItems": 50 },
          "channel": { "type": ["string", "null"], "enum": ["META", "GOOGLE", "ORGANICO", "INDICACAO", "OUTRO", null], "description": "Origem de marketing. Aceita minúsculas." },
          "campaign": { "type": ["string", "null"], "maxLength": 200 },
          "ad": { "type": ["string", "null"], "maxLength": 200 },
          "channelMeta": { "type": ["object", "null"], "additionalProperties": true, "description": "Objeto livre com o payload bruto da plataforma, gravado no negócio. Só no create — não volta na resposta nem é editável depois." },
          "ramal": { "$ref": "#/components/schemas/Ramal" }
        }
      },
      "DealPatch": {
        "type": "object",
        "required": ["unitId"],
        "properties": {
          "unitId": { "type": "string" },
          "title": { "type": "string", "maxLength": 140 },
          "valueMinor": { "type": "integer", "minimum": 0, "maximum": 2147483647 },
          "stageId": { "type": "string", "description": "Estágio do funil do negócio. Prevalece sobre status." },
          "status": { "type": "string", "enum": ["won", "lost", "open"], "description": "Atalho: won → estágio Fechado, lost → estágio Perdido, open → 1º estágio aberto." },
          "lostReason": { "type": ["string", "null"], "maxLength": 500 },
          "ownerMembershipId": { "type": "string" },
          "channel": { "type": ["string", "null"], "enum": ["META", "GOOGLE", "ORGANICO", "INDICACAO", "OUTRO", null], "description": "Origem de marketing. Aceita minúsculas; null limpa." },
          "campaign": { "type": ["string", "null"], "maxLength": 200, "description": "null limpa." },
          "ad": { "type": ["string", "null"], "maxLength": 200, "description": "null limpa." },
          "ramal": { "$ref": "#/components/schemas/Ramal" }
        }
      },
      "Activity": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "unitId": { "type": "string" },
          "type": { "type": "string", "enum": ["CALL", "MEETING", "TASK", "DEADLINE", "WHATSAPP"] },
          "title": { "type": "string" },
          "dueAt": { "type": "string", "format": "date-time" },
          "doneAt": { "type": ["string", "null"], "format": "date-time" },
          "ownerMembershipId": { "type": "string" },
          "dealId": { "type": ["string", "null"] },
          "contactId": { "type": ["string", "null"] },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "ActivityCreate": {
        "type": "object",
        "required": ["unitId", "type", "title", "dueAt"],
        "properties": {
          "unitId": { "type": "string" },
          "type": { "type": "string", "enum": ["CALL", "MEETING", "TASK", "DEADLINE", "WHATSAPP"] },
          "title": { "type": "string", "maxLength": 140 },
          "dueAt": { "type": "string", "format": "date-time" },
          "doneAt": { "type": ["string", "null"], "format": "date-time", "description": "Funciona como sinal: presente, a atividade nasce e é marcada feita na hora do servidor (o instante enviado não é gravado). Dispara activity.done." },
          "ownerMembershipId": { "type": ["string", "null"], "description": "Padrão: quem criou a chave." },
          "contactId": { "type": ["string", "null"] },
          "notes": { "type": ["string", "null"], "maxLength": 2000 }
        }
      },
      "Contact": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "phone": { "type": ["string", "null"], "description": "DDI+DDD+número, só dígitos" },
          "email": { "type": ["string", "null"] },
          "instagramHandle": { "type": ["string", "null"] },
          "organizationId": { "type": ["string", "null"] },
          "unitIds": { "type": "array", "items": { "type": "string" }, "description": "Só as unidades que a chave alcança." },
          "ramalContactId": { "type": ["string", "null"] },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "ContactUpsert": {
        "type": "object",
        "required": ["unitId"],
        "description": "Pelo menos phone ou name. Unificação: ramalContactId (se enviado), senão phone.",
        "properties": {
          "unitId": { "type": "string" },
          "phone": { "type": ["string", "null"], "description": "DDI+DDD+número, só dígitos (ex.: 5521999998888)" },
          "name": { "type": ["string", "null"], "maxLength": 140 },
          "email": { "type": ["string", "null"], "maxLength": 200 },
          "instagramHandle": { "type": ["string", "null"], "maxLength": 80 },
          "notes": { "type": ["string", "null"], "maxLength": 2000 },
          "organizationId": { "type": ["string", "null"] },
          "ramalContactId": { "type": ["string", "null"] }
        }
      },
      "WebhookEnvelope": {
        "type": "object",
        "description": "Corpo dos webhooks de saída (headers x-elo-event, x-elo-delivery, x-elo-timestamp, x-elo-signature; User-Agent Elo-Webhooks/1.0).",
        "properties": {
          "id": { "type": "string" },
          "event": { "type": "string", "enum": ["deal.created", "deal.stage_changed", "deal.won", "deal.lost", "activity.done", "contact.upserted", "ping"] },
          "createdAt": { "type": "string", "format": "date-time" },
          "attempt": { "type": "integer" },
          "account": { "type": "object", "properties": { "id": { "type": "string" } } },
          "unit": { "oneOf": [{ "$ref": "#/components/schemas/UnitRef" }, { "type": "null" }] },
          "data": { "type": "object" }
        }
      },
      "LeadInbound": {
        "type": "object",
        "description": "Lead da entrada genérica. Pelo menos um entre name, phone e email.",
        "properties": {
          "name": { "type": ["string", "null"], "maxLength": 140 },
          "phone": { "type": ["string", "null"], "maxLength": 40, "description": "O Elo limpa máscara (fica só dígitos). É a chave de dedupe do contato." },
          "email": { "type": ["string", "null"], "maxLength": 200, "description": "Dedupe quando não há telefone." },
          "channel": { "type": ["string", "null"], "maxLength": 40, "description": "Texto livre — o Elo entende sinônimos (facebook/ig → META, google ads → GOOGLE, indicação → INDICACAO…). Sem channel, vale o canal configurado na entrada." },
          "campaign": { "type": ["string", "null"], "maxLength": 200 },
          "ad": { "type": ["string", "null"], "maxLength": 200 },
          "title": { "type": ["string", "null"], "maxLength": 140, "description": "Título do negócio. Padrão: \"Novo lead — <nome>\"." },
          "valueMinor": { "type": ["integer", "null"], "minimum": 0, "maximum": 2147483647 },
          "meta": { "type": ["object", "null"], "additionalProperties": true, "description": "Objeto livre gravado no negócio (channelMeta)." }
        }
      },
      "LeadIngestResult": {
        "type": "object",
        "required": ["ok", "contactId", "dealId", "duplicated"],
        "properties": {
          "ok": { "type": "boolean" },
          "contactId": { "type": "string" },
          "dealId": { "type": "string" },
          "duplicated": { "type": "boolean", "description": "true (status 200) = o contato já tinha negócio aberto na unidade — o lead virou atividade no negócio existente, não negócio novo (201)." }
        }
      }
    },
    "responses": {
      "Error": { "description": "Erro", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "DealItem": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "$ref": "#/components/schemas/Deal" } } } } } }
    }
  },
  "paths": {
    "/units": {
      "get": {
        "summary": "Unidades ativas que a chave alcança (rota de descoberta; não exige unitId)",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "type": "null" }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/Unit" } } } } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/deals": {
      "get": {
        "summary": "Negócios da unidade (mais recentes primeiro)",
        "parameters": [
          { "$ref": "#/components/parameters/unitId" },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["open", "won", "lost"] } },
          { "name": "stageId", "in": "query", "schema": { "type": "string" } },
          { "name": "contactId", "in": "query", "schema": { "type": "string" } },
          { "name": "ownerMembershipId", "in": "query", "schema": { "type": "string" } },
          { "name": "channel", "in": "query", "schema": { "type": "string", "enum": ["META", "GOOGLE", "ORGANICO", "INDICACAO", "OUTRO"] }, "description": "Filtra pela origem de marketing." },
          { "$ref": "#/components/parameters/cursor" },
          { "$ref": "#/components/parameters/limit" }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/Deal" } }, "nextCursor": { "type": ["string", "null"] } } } } } },
          "400": { "$ref": "#/components/responses/Error" }
        }
      },
      "post": {
        "summary": "Negócio novo (dispara deal.created)",
        "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealCreate" } } } },
        "responses": { "201": { "$ref": "#/components/responses/DealItem" }, "400": { "$ref": "#/components/responses/Error" }, "409": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/deals/{id}": {
      "get": {
        "summary": "Um negócio da unidade",
        "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/unitId" }],
        "responses": { "200": { "$ref": "#/components/responses/DealItem" }, "404": { "$ref": "#/components/responses/Error" } }
      },
      "patch": {
        "summary": "Atualiza título, valor, estágio/status, motivo de perda, dono ou vínculos Ramal (fechar dispara deal.won; perder, deal.lost)",
        "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/idempotencyKey" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/DealItem" }, "400": { "$ref": "#/components/responses/Error" }, "404": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/deals/{id}/activities": {
      "post": {
        "summary": "Atividade no negócio (com doneAt, já nasce feita e dispara activity.done)",
        "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/idempotencyKey" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityCreate" } } } },
        "responses": {
          "201": { "description": "Criada", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "$ref": "#/components/schemas/Activity" } } } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/contacts": {
      "get": {
        "summary": "Contatos vinculados à unidade",
        "parameters": [
          { "$ref": "#/components/parameters/unitId" },
          { "name": "q", "in": "query", "schema": { "type": "string" }, "description": "nome / e-mail / @instagram / dígitos do telefone" },
          { "name": "phone", "in": "query", "schema": { "type": "string" }, "description": "busca exata, só dígitos" },
          { "name": "ramalContactId", "in": "query", "schema": { "type": "string" } },
          { "$ref": "#/components/parameters/cursor" },
          { "$ref": "#/components/parameters/limit" }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/Contact" } }, "nextCursor": { "type": ["string", "null"] } } } } } },
          "400": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/contacts/upsert": {
      "post": {
        "summary": "Cria ou atualiza (ramalContactId, senão telefone) e vincula à unidade — dispara contact.upserted",
        "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactUpsert" } } } },
        "responses": {
          "200": { "description": "Atualizado", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "$ref": "#/components/schemas/Contact" }, "created": { "type": "boolean" } } } } } },
          "201": { "description": "Criado", "content": { "application/json": { "schema": { "type": "object", "properties": { "unit": { "$ref": "#/components/schemas/UnitRef" }, "data": { "$ref": "#/components/schemas/Contact" }, "created": { "type": "boolean" } } } } } },
          "400": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/webhooks/leads/{inboxId}": {
      "servers": [{ "url": "https://elo.foxgrid.com.br" }],
      "post": {
        "summary": "Entrada genérica de leads (site, Zapier, Make) — cria contato + negócio com origem",
        "description": "Sem Bearer: token da entrada no header x-elo-token (ou ?token=). O negócio nasce com source FORM e channel/campaign/ad preenchidos. Dedupe: contato com negócio aberto na mesma unidade vira atividade no negócio existente (200, duplicated: true) em vez de negócio novo (201). Primeira origem do contato nunca é sobrescrita. Limite: 120 leads/min por entrada.",
        "security": [{ "inboxToken": [] }],
        "parameters": [{ "$ref": "#/components/parameters/inboxId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadInbound" } } } },
        "responses": {
          "201": { "description": "Negócio novo criado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadIngestResult" } } } },
          "200": { "description": "Dedupe — virou atividade no negócio aberto existente", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadIngestResult" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/webhooks/leads/{inboxId}/google": {
      "servers": [{ "url": "https://elo.foxgrid.com.br" }],
      "post": {
        "summary": "Webhook nativo do Google Ads Lead Form",
        "description": "Sem header de auth: o Google manda a chave no payload (google_key = token da entrada; configure como \"Chave\" na entrega de leads via webhook). O Elo mapeia user_column_data (FULL_NAME/FIRST_NAME/LAST_NAME, PHONE_NUMBER, EMAIL; demais respostas vão para channelMeta.respostas), fixa channel GOOGLE e usa campaign_id como campanha. Mesma resposta e dedupe da entrada genérica.",
        "security": [],
        "parameters": [{ "$ref": "#/components/parameters/inboxId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "description": "Payload nativo do Google Ads Lead Form: google_key, lead_id, form_id, campaign_id, gcl_id, is_test, user_column_data[{ column_id, column_name, string_value }]." } } } },
        "responses": {
          "201": { "description": "Negócio novo criado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadIngestResult" } } } },
          "200": { "description": "Dedupe — virou atividade no negócio aberto existente", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadIngestResult" } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/webhooks/leads/{inboxId}/meta": {
      "servers": [{ "url": "https://elo.foxgrid.com.br" }],
      "get": {
        "summary": "Verificação do webhook do Meta (hub.challenge)",
        "description": "hub.mode=subscribe + hub.verify_token = token da entrada → devolve hub.challenge em text/plain; 403 se não confere.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/inboxId" },
          { "name": "hub.mode", "in": "query", "schema": { "type": "string" } },
          { "name": "hub.verify_token", "in": "query", "schema": { "type": "string" } },
          { "name": "hub.challenge", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "hub.challenge", "content": { "text/plain": { "schema": { "type": "string" } } } },
          "403": { "$ref": "#/components/responses/Error" }
        }
      },
      "post": {
        "summary": "Leads do Meta Lead Ads (leadgen)",
        "description": "Sem header de token: assinado com X-Hub-Signature-256: sha256=HMAC-SHA256(app secret da entrada, corpo bruto) — sem app secret configurado, 409; assinatura errada, 401. A notificação leadgen só traz o id do lead: o Elo busca o lead completo (field_data, campaign_name, ad_name) no Graph API com o page access token da entrada; field_data inline (pontes Zapier/Make, Lead Ads Testing Tool) dispensa o Graph. Com assinatura válida a resposta é sempre 200 — senão o Meta re-entrega o lote em loop; falha de lead individual fica no diagnóstico da entrada.",
        "security": [],
        "parameters": [{ "$ref": "#/components/parameters/inboxId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "description": "Notificação leadgen do Meta: entry[].changes[].value ({ leadgen_id, page_id, form_id, ad_id, field_data? })." } } } },
        "responses": {
          "200": { "description": "Processado (ok=false quando algum lead falhou — detalhe no diagnóstico da entrada)", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "processed": { "type": "integer" }, "failed": { "type": "integer" } } } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "409": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  }
}
