{
  "openapi": "3.1.0",
  "info": {
    "title": "Reportei Connect API",
    "version": "1.0.0",
    "description": "Coleta de métricas de redes sociais, plataformas de anúncios, CRMs e e-commerces por uma API só, sem implementar OAuth de nenhuma delas.\n\n## O modelo\n\n```\nmerchant  →  customers  →  integration session  →  métricas\n```\n\n- **merchant** é a conta que integra. Uma chave de API, que autentica tudo.\n- **customer** é cada cliente do merchant. Criado pela API, e cada um tem um token próprio.\n- **integration session** é o link temporário onde o customer autoriza as contas dele.\n- **métricas** são pedidas informando qual conexão daquele customer se quer ler.\n\nO que existe para pedir não depende de cliente nenhum: `GET /integrations` lista as plataformas e `GET /metrics/{integration_slug}` lista as métricas de cada uma.\n\n## Autenticação\n\nDois headers, que não são a mesma coisa. `Authorization: Bearer` identifica o merchant e vai em toda requisição. `x-customer-token` restringe a chamada a um cliente, e vale só nos endpoints marcados com ele. Errar essa distinção é a causa mais comum de 401 nesta API.\n\nO token do customer é devolvido **uma única vez**, na criação. Não há endpoint que o recupere.\n\n## Erros\n\nEsta API usa **três** envelopes de erro diferentes, e a distinção é observável:\n\n| Origem | Corpo |\n|---|---|\n| Validação de Form Request | `{\"errors\": {\"campo\": [\"mensagem\"]}}` |\n| Validação lançada fora do Form Request (métricas) | `{\"message\": \"...\", \"extra\": ...}` |\n| Todo o resto | `{\"message\": \"...\"}` |\n\nRamifique pelo status HTTP, e no 422 verifique qual das duas chaves veio.\n\n**Um recurso desconhecido responde 403, não 404.** A checagem de posse (`model_merchant_permission`) não distingue \"não existe\" de \"não é seu\", e responde `This action is unauthorized.` nos dois casos.\n\n## Limites\n\nO rate limit é por merchant, configurado por conta, e devolve 429. Além dele, uma conta com o período de teste encerrado e sem pagamento recebe 403 em toda a API.",
    "contact": {
      "name": "Reportei",
      "url": "https://lp.connect.reportei.com"
    }
  },
  "servers": [
    {
      "url": "https://connect.reportei.com/api",
      "description": "Produção"
    }
  ],
  "tags": [
    {
      "name": "Merchant",
      "description": "A conta que integra"
    },
    {
      "name": "Customers",
      "description": "Os clientes do merchant"
    },
    {
      "name": "Customer Integrations",
      "description": "As conexões de um cliente com as plataformas"
    },
    {
      "name": "Metrics",
      "description": "Leitura das métricas de uma conexão"
    },
    {
      "name": "Ads",
      "description": "Gestão de anúncios nas contas de ads dos seus clientes.\n\n**IDs.** Onde um endpoint de ads pede um id, vale tanto o `uuid` do Connect quanto o `id` do objeto, o numérico que a plataforma de anúncios deu à campanha, ao conjunto ou ao anúncio (na Meta, o mesmo do Gerenciador de Anúncios). Isso inclui o `{id}` da rota, o `id` de um nível no corpo (`campaign: { \"id\": … }`) e filtros como `campaign_id`. O `id` funciona para qualquer objeto da conta. O `uuid` só funciona para os que o Connect guarda. As respostas trazem os dois: `id` é o do objeto e `uuid` é o do Connect, que vem `null` quando o objeto não está no Connect.\n\n**Campos de cada integração.** Em cada nível, os campos que toda integração de anúncios tem ficam no topo (`name`, `status`, `budget`, `schedule`, `targeting`…). O que é só de uma integração vai num bloco com o nome do `integration_slug` dela. Hoje esse bloco é `facebook_ads: { … }`. O conteúdo do bloco é da integração e pode ganhar campos novos. Outra integração terá o próprio bloco, com campos diferentes (por exemplo, `google_ads: { … }`), e os campos do topo continuam os mesmos. Os campos e valores aceitos em cada bloco estão em `GET /ads/options?integration_slug=`."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/merchants/settings": {
      "get": {
        "tags": [
          "Merchant"
        ],
        "operationId": "getMerchantSettings",
        "summary": "A conta, seus limites e as plataformas liberadas",
        "description": "O teste de fumaça de uma integração nova: 200 aqui significa que a chave é válida, a conta está ativa e a API está respondendo.\n\n`available_integrations` é o que o plano do merchant libera: o que ele pode oferecer aos clientes dele.\n\nO catálogo inteiro da plataforma, liberado ou não, está em `GET /integrations`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A conta e suas configurações",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "merchant",
                    "include_settings"
                  ],
                  "properties": {
                    "merchant": {
                      "$ref": "#/components/schemas/MerchantSettings"
                    },
                    "include_settings": {
                      "type": "boolean",
                      "const": true,
                      "description": "Constante. Sinaliza que o payload traz o bloco de configurações; não é um campo de decisão."
                    }
                  }
                },
                "example": {
                  "merchant": {
                    "uuid": "c1e6c85a-6441-4107-ab36-b8bf581b40e0",
                    "name": "Reportei",
                    "app_url": "https://reportei.com",
                    "redirect_url": "https://reportei.com/callback",
                    "logo_url": null,
                    "trial_ends_at": "2026-09-16T17:15:12.000000Z",
                    "is_paying": true,
                    "created_at": "2026-09-02 17:07:26",
                    "updated_at": "2026-09-02 17:07:26",
                    "rate_limit_per_minute": "300",
                    "rate_limit_per_second": "10",
                    "total_customers": 2,
                    "available_integrations": [
                      {
                        "name": "Instagram Business",
                        "slug": "instagram_business"
                      },
                      {
                        "name": "Meta Ads",
                        "slug": "facebook_ads"
                      }
                    ]
                  },
                  "include_settings": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/integrations": {
      "get": {
        "tags": [
          "Merchant"
        ],
        "operationId": "listIntegrations",
        "summary": "O catálogo de plataformas do Connect",
        "description": "Tudo que o Connect sabe coletar, liberado ou não para esta conta. O que o plano do merchant libera está em `available_integrations` de `/merchants/settings`, e é esse subconjunto que ele pode oferecer aos clientes dele.\n\nO `slug` de cada item é o que `GET /metrics/{integration_slug}` recebe, e o que a sessão de integração aceita em `available_integrations`.\n\nÉ uma lista completa, sem paginação.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "O catálogo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Integration"
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 1,
                      "name": "Instagram Business",
                      "slug": "instagram_business",
                      "type": 1,
                      "color": "#FC4ADE",
                      "icon": {
                        "name": "social.instagram_business",
                        "color": "pink-600"
                      },
                      "enabled": true,
                      "created_at": "2024-09-13 14:12:56",
                      "updated_at": "2024-09-13 14:12:56"
                    },
                    {
                      "id": 3,
                      "name": "Meta Ads",
                      "slug": "facebook_ads",
                      "type": 3,
                      "color": "#0668E1",
                      "icon": {
                        "name": "social.meta_ads",
                        "color": "indigo-600"
                      },
                      "enabled": true,
                      "created_at": "2024-09-13 14:12:56",
                      "updated_at": "2024-09-13 14:12:56"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers": {
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "listCustomers",
        "summary": "Lista os clientes do merchant",
        "description": "Sempre restrito aos clientes da conta autenticada.\n\nAlém dos parâmetros documentados, qualquer nome de coluna da tabela funciona como filtro `LIKE`. Isso é comportamento genérico da camada de listagem, não contrato. Não construa sua integração sobre ele.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/SortBy"
          },
          {
            "$ref": "#/components/parameters/Descending"
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filtro parcial pelo nome do cliente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de clientes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "uuid": "caedbbbe-7d93-476f-b965-bf97cd7ce874",
                      "name": "Cliente 1",
                      "created_at": "2026-09-02 17:07:34",
                      "updated_at": "2026-09-02 17:07:34",
                      "trial_ends_at": "2026-09-16 17:07:34",
                      "is_paying": false,
                      "merchant": "Reportei"
                    }
                  ],
                  "meta": {
                    "current_page": 1,
                    "from": 1,
                    "last_page": 1,
                    "path": "https://connect.reportei.com/api/customers",
                    "per_page": 15,
                    "to": 1,
                    "total": 1,
                    "sortBy": null,
                    "descending": false
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Customers"
        ],
        "operationId": "createCustomer",
        "summary": "Cria um cliente",
        "description": "**A resposta traz `api_token`, e essa é a única vez que ele aparece.** É o valor do header `x-customer-token` desse cliente. Nenhum outro endpoint o devolve, e não há como recuperá-lo. Persista-o junto ao registro do cliente, na mesma transação em que você o cria.\n\nO período de teste do cliente é definido pela API em 14 dias a partir da criação. `is_paying` começa falso e só muda pelo endpoint de status de pagamento.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Nome do cliente. Não precisa ser único."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "name": "Cliente 1"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cliente criado. **Contém o token do cliente.**",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer"
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/CustomerCreated"
                    }
                  }
                },
                "example": {
                  "customer": {
                    "uuid": "caedbbbe-7d93-476f-b965-bf97cd7ce874",
                    "name": "Cliente 1",
                    "created_at": "2026-09-02 17:07:34",
                    "updated_at": "2026-09-02 17:07:34",
                    "trial_ends_at": "2026-09-16 17:07:34",
                    "is_paying": false,
                    "merchant": "Reportei",
                    "api_token": "8f14e45fceea167a5a36dedd4bea2543a1b2c3d4e5f60718293a4b5c6d7e8f90"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "422": {
            "description": "Validação. `is_paying`, `trial_ends_at` e `api_token` são do servidor e são recusados se enviados: o status de pagamento tem endpoint próprio, o trial é fixado na criação e o token é gerado pelo Connect.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "examples": {
                  "nome_ausente": {
                    "value": {
                      "errors": {
                        "name": [
                          "The name field is required."
                        ]
                      }
                    }
                  },
                  "campo_proibido": {
                    "value": {
                      "errors": {
                        "is_paying": [
                          "The is paying field is prohibited."
                        ],
                        "trial_ends_at": [
                          "The trial ends at field is prohibited."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers/settings": {
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "getCustomerSettings",
        "summary": "O cliente do token, com as conexões dele",
        "description": "Identifica o cliente pelo `x-customer-token`, então não recebe uuid. É o caminho para descobrir o que o cliente conectou e o `uuid` de cada conexão, que é o que os endpoints de métricas pedem.\n\nDiferente dos endpoints de sessão e de métricas, este **continua respondendo** para um cliente com o período de teste encerrado.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "O cliente e suas conexões",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer",
                    "include_settings"
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/CustomerWithIntegrations"
                    },
                    "include_settings": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                },
                "example": {
                  "customer": {
                    "uuid": "073c1e15-94d0-49b3-9861-a0e9b7ffb06c",
                    "name": "Cliente 1",
                    "created_at": "2026-09-02 19:06:08",
                    "updated_at": "2026-09-02 19:06:08",
                    "trial_ends_at": "2026-09-16 19:06:08",
                    "is_paying": false,
                    "merchant": "Reportei",
                    "integrations": [
                      {
                        "uuid": "6110b666-0327-4a81-b48e-9feb34d72f78",
                        "integration": "Instagram Business",
                        "name": "reportei",
                        "slug": "instagram_business",
                        "status": "active",
                        "icon": {
                          "name": "social.instagram_business",
                          "color": "pink-600"
                        }
                      }
                    ]
                  },
                  "include_settings": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerTokenError"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers/{uuid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CustomerUuid"
        }
      ],
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "getCustomer",
        "summary": "Um cliente",
        "description": "Os dados de um cliente seu, pelo `uuid`. Não traz as conexões. Para isso, use `GET /customer-integrations` com o token do cliente, ou `GET /customers/integrations` para ver todos de uma vez.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "O cliente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer"
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Customers"
        ],
        "operationId": "updateCustomer",
        "summary": "Renomeia um cliente",
        "description": "`name` é obrigatório também em `PATCH`: não há atualização parcial.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  }
                }
              },
              "example": {
                "name": "Novo nome"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "O cliente atualizado. Sem `api_token`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer"
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Validação. Como na criação, `is_paying`, `trial_ends_at` e `api_token` são recusados se enviados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Customers"
        ],
        "operationId": "patchCustomer",
        "summary": "Renomeia um cliente",
        "description": "Idêntico ao `PUT` desta mesma rota: a aplicação registra os dois verbos no mesmo tratador.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  }
                }
              },
              "example": {
                "name": "Novo nome"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "O cliente atualizado. Sem `api_token`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer"
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Validação. Como na criação, `is_paying`, `trial_ends_at` e `api_token` são recusados se enviados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Customers"
        ],
        "operationId": "deleteCustomer",
        "summary": "Remove um cliente e as conexões dele",
        "description": "Irreversível, e cascateia nas conexões. O token daquele cliente deixa de valer.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Removido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessage"
                },
                "example": {
                  "success": true,
                  "message": "Record successfully removed"
                }
              }
            }
          },
          "400": {
            "description": "A remoção falhou no banco",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FailureMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers/{uuid}/update-payment-status": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CustomerUuid"
        }
      ],
      "post": {
        "tags": [
          "Customers"
        ],
        "operationId": "updateCustomerPaymentStatus",
        "summary": "Marca o cliente como pagante, ou deixa de marcar",
        "description": "É como um cliente continua acessível depois dos 14 dias de teste.\n\n**Não é idempotente por decisão da API:** enviar o estado que o cliente já tem responde 422. Leia o estado atual antes, ou trate o 422 como \"já estava assim\".",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_paying"
                ],
                "properties": {
                  "is_paying": {
                    "type": "boolean",
                    "description": "Precisa ser diferente do estado atual do cliente."
                  }
                }
              },
              "example": {
                "is_paying": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status alterado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessage"
                },
                "example": {
                  "success": true,
                  "message": "Customer is now marked as a paying customer"
                }
              }
            }
          },
          "400": {
            "description": "A alteração falhou",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FailureMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Validação, incluindo o estado repetido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "is_paying": [
                      "The customer is already marked as paying."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customer-integrations/session": {
      "post": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "createIntegrationSession",
        "summary": "Abre a tela onde o cliente autoriza as contas dele",
        "description": "Devolve `session_link`. Leve o cliente até essa URL: é lá que ele faz o login na plataforma e escolhe as contas, sem que você implemente OAuth.\n\n**Cada chamada invalida a sessão anterior** daquele par merchant/cliente. Não abra duas em paralelo para o mesmo cliente.\n\nA sessão expira em 5 minutos por padrão, e `expires_in_minutes` ajusta isso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Todos os campos são opcionais. Um corpo vazio é válido.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegrationSessionRequest"
              },
              "examples": {
                "minimo": {
                  "value": {}
                },
                "com_limites": {
                  "summary": "Restringindo o que o cliente vê e quantas contas conecta",
                  "value": {
                    "redirect_url": "https://sua-aplicacao.com/dashboard",
                    "locale": "pt_BR",
                    "close_on_finish": true,
                    "limits": [
                      {
                        "name": "integration_count",
                        "value": 3
                      },
                      {
                        "name": "available_integrations",
                        "value": [
                          "instagram_business",
                          "facebook_ads"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sessão aberta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "integration_session"
                  ],
                  "properties": {
                    "integration_session": {
                      "$ref": "#/components/schemas/IntegrationSession"
                    }
                  }
                },
                "example": {
                  "integration_session": {
                    "session_uuid": "b1f0f8e0-3a1e-4a1b-9c2d-7e8f90a1b2c3",
                    "session_link": "https://connect.reportei.com/customer-integrations/session/b1f0f8e0-3a1e-4a1b-9c2d-7e8f90a1b2c3",
                    "expires_at": "2026-09-02T17:12:26.000000Z",
                    "merchant": "Reportei",
                    "merchant_uuid": "c1e6c85a-6441-4107-ab36-b8bf581b40e0",
                    "customer": "Cliente 1",
                    "customer_uuid": "caedbbbe-7d93-476f-b965-bf97cd7ce874",
                    "redirect_url": "https://sua-aplicacao.com/dashboard",
                    "close_on_finish": true,
                    "locale": "pt_BR",
                    "limits": [
                      {
                        "name": "integration_count",
                        "value": 3
                      }
                    ],
                    "limit_reached_url": null,
                    "enable_multi_account_selection": false
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "422": {
            "description": "Validação",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customer-integrations": {
      "get": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "listCustomerIntegrations",
        "summary": "Lista as conexões do cliente",
        "description": "As conexões do cliente do `x-customer-token`, e o único jeito de descobrir o `uuid` de cada uma, que é o que os endpoints de métricas pedem. Rode este endpoint depois que o cliente voltar da sessão de autorização.\n\nAlém dos parâmetros documentados, qualquer nome de coluna da tabela funciona como filtro `LIKE`. Isso é comportamento genérico da camada de listagem, não contrato. Não construa sua integração sobre ele.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/SortBy"
          },
          {
            "$ref": "#/components/parameters/Descending"
          },
          {
            "name": "source_name",
            "in": "query",
            "required": false,
            "description": "Filtro parcial pelo nome da conta conectada.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filtro pelo estado da conexão.",
            "schema": {
              "$ref": "#/components/schemas/IntegrationStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de conexões",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerIntegration"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "uuid": "4addc0da-8583-4dbb-a0e9-c7e2e8470f50",
                      "source_id": "17841400000000000",
                      "source_name": "reportei",
                      "status": "active",
                      "created_at": "2026-09-02 17:08:08",
                      "updated_at": "2026-09-02 17:08:08",
                      "email": null,
                      "profile_picture_url": null,
                      "integration": {
                        "name": "Instagram Business",
                        "slug": "instagram_business"
                      }
                    }
                  ],
                  "meta": {
                    "current_page": 1,
                    "from": 1,
                    "last_page": 1,
                    "path": "https://connect.reportei.com/api/customer-integrations",
                    "per_page": 15,
                    "to": 1,
                    "total": 1,
                    "sortBy": null,
                    "descending": false
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerTokenError"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customer-integrations/{uuid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/IntegrationUuid"
        }
      ],
      "get": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "getCustomerIntegration",
        "summary": "Uma conexão do cliente",
        "description": "A conexão precisa pertencer ao cliente do `x-customer-token`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "A conexão",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "customer_integration"
                  ],
                  "properties": {
                    "customer_integration": {
                      "$ref": "#/components/schemas/CustomerIntegration"
                    }
                  }
                },
                "example": {
                  "customer_integration": {
                    "uuid": "4addc0da-8583-4dbb-a0e9-c7e2e8470f50",
                    "source_id": "17841400000000000",
                    "source_name": "reportei",
                    "status": "active",
                    "created_at": "2026-09-02 17:08:08",
                    "updated_at": "2026-09-02 17:08:08",
                    "email": null,
                    "profile_picture_url": null,
                    "integration": {
                      "name": "Instagram Business",
                      "slug": "instagram_business"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerTokenError"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "deleteCustomerIntegration",
        "summary": "Remove uma conexão do cliente",
        "description": "**Este endpoint autentica de forma diferente de todos os outros.** Ele não usa `Authorization: Bearer` nem `x-customer-token`: a autorização é a sessão de integração, passada em `session_id` na query string. É o endpoint que a própria tela de autorização chama, e a conexão precisa pertencer ao cliente daquela sessão.\n\nSem um `session_id` válido e não expirado, responde 401.",
        "security": [],
        "parameters": [
          {
            "name": "session_id",
            "in": "query",
            "required": true,
            "description": "`session_uuid` de uma integration session válida e não expirada.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessage"
                },
                "example": {
                  "success": true,
                  "message": "Record successfully removed"
                }
              }
            }
          },
          "400": {
            "description": "A remoção falhou",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FailureMessage"
                }
              }
            }
          },
          "401": {
            "description": "Sessão ausente, inválida ou expirada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Session is expired or invalid"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          }
        }
      }
    },
    "/metrics/{integration_slug}": {
      "get": {
        "tags": [
          "Metrics"
        ],
        "operationId": "listMetricDefinitions",
        "summary": "As métricas que uma plataforma oferece",
        "description": "O catálogo de uma plataforma: cada `reference_key` disponível, com o `component`, as `metrics` e as `dimensions` padrão. **Cada item de `data` já é um MetricRequestItem válido**: copie-o para `metrics[]` de `/metrics/get-data` e a consulta funciona. Para pedir outro valor ou detalhamento, troque `metrics`/`dimensions` por chaves de `meta.setup`.\n\nSó a chave do merchant: o catálogo é o mesmo para todo cliente e toda conexão. Descubra o `integration_slug` em `GET /integrations` ou no `slug` das conexões do cliente.\n\nA resposta é estável por semanas e cacheada do lado do Connect, então busque-a uma vez e guarde, não a cada consulta de métrica.\n\nUma conta pode ter métricas restritas por contrato; nesse caso `/metrics/get-data` recusa a chave com 422 e a nomeia na mensagem. O catálogo não reflete essa restrição.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "integration_slug",
            "in": "path",
            "required": true,
            "description": "O `slug` da plataforma, como devolvido por `GET /integrations`.",
            "schema": {
              "type": "string"
            },
            "example": "facebook_ads"
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Idioma de `references` e dos `label` em `meta.setup`. Não muda nenhuma chave.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "pt_br",
                "es",
                "fr",
                "it",
                "de"
              ],
              "default": "en"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "O catálogo da plataforma",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MetricDefinition"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "integration_slug",
                        "language",
                        "setup"
                      ],
                      "properties": {
                        "integration_slug": {
                          "type": "string"
                        },
                        "language": {
                          "type": "string"
                        },
                        "setup": {
                          "$ref": "#/components/schemas/MetricDefinitionsSetup"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "c45d148c-0d07-4473-b7d7-f886c8b56884",
                      "reference_key": "fb_ads:spend",
                      "component": "number_v1",
                      "metrics": [
                        "spend"
                      ],
                      "dimensions": [],
                      "references": {
                        "title": "Valor investido",
                        "description": "O valor total estimado que você gastou na sua campanha, conjunto de anúncios ou anúncio durante seu agendamento.",
                        "tags": {
                          "cost": "pago",
                          "history": "retroativo"
                        }
                      }
                    },
                    {
                      "id": "80e06171-759e-472e-9cff-25ae8e91e1e0",
                      "reference_key": "fb_ads:insights_by_campaign",
                      "component": "datatable_v1",
                      "metrics": [
                        "results",
                        "cost_per_results",
                        "spend",
                        "reach",
                        "impressions",
                        "ctr",
                        "cpc",
                        "cpm",
                        "frequency"
                      ],
                      "dimensions": [
                        {
                          "field": "campaign"
                        }
                      ],
                      "references": {
                        "title": "Campanhas em destaque",
                        "description": "Campanhas que tiveram o maior impacto em sua audiência, no período analisado.",
                        "tags": {
                          "cost": "pago",
                          "history": "retroativo"
                        }
                      }
                    }
                  ],
                  "meta": {
                    "integration_slug": "facebook_ads",
                    "language": "pt_br",
                    "setup": {
                      "metrics": {
                        "spend": {
                          "label": "Valor investido"
                        },
                        "results": {
                          "label": "Resultados"
                        },
                        "reach": {
                          "label": "Alcance"
                        },
                        "impressions": {
                          "label": "Impressões"
                        }
                      },
                      "dimensions": {
                        "campaign": {
                          "label": "Nome da Campanha"
                        },
                        "publisher_platform": {
                          "label": "Plataforma"
                        },
                        "date": {
                          "label": "Data"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/MerchantAccessDenied"
          },
          "404": {
            "description": "Slug que não existe no catálogo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "error_code"
                  ],
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "error_code": {
                      "type": "string",
                      "const": "not_found"
                    }
                  }
                },
                "example": {
                  "message": "Integration slug 'meta_ads' not found",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "`language` fora da lista aceita",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "language": [
                      "The selected language is invalid."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "O catálogo não pôde ser lido agora. Nada foi cacheado; tente de novo em instantes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Metric catalog is temporarily unavailable, please try again"
                }
              }
            }
          }
        }
      }
    },
    "/metrics/get-data": {
      "post": {
        "tags": [
          "Metrics"
        ],
        "operationId": "getMetrics",
        "summary": "Lê métricas de uma ou mais conexões",
        "description": "Síncrono. Para períodos longos ou muitas métricas, prefira a versão assíncrona: aqui a requisição fica aberta enquanto a coleta acontece.\n\nInforme **ou** `customer_integration` (uma conexão) **ou** `customer_integration_uuids` (várias). Todas têm de pertencer ao cliente do `x-customer-token`.\n\nO formato de cada métrica depende do `component` pedido, e por isso o payload de resposta é aberto: a chave de cada item é o `id` que você enviou, e o valor é o resultado daquela métrica.\n\nOs `reference_key` disponíveis variam por plataforma. Descubra-os em `GET /metrics/{integration_slug}`: cada item de lá já vem na forma que este endpoint aceita em `metrics[]`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetricsRequest"
              },
              "example": {
                "customer_integration": "4addc0da-8583-4dbb-a0e9-c7e2e8470f50",
                "start": "2026-08-01",
                "end": "2026-08-31",
                "metrics": [
                  {
                    "id": "f35a44ce-dac5-4188-aace-5c44a8952176",
                    "reference_key": "ig:story_replies",
                    "component": "number_v1",
                    "metrics": [
                      "replies"
                    ],
                    "dimensions": [
                      "stories"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "As métricas, indexadas pelo `id` que você enviou",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "description": "Mapa de `id` da métrica para o resultado dela. O formato do resultado depende do `component`. Quando uma métrica falha isoladamente, o valor é um objeto de erro em vez do resultado (ver MetricFailure).",
                      "additionalProperties": {
                        "description": "O resultado daquela métrica, cuja forma depende do `component` pedido, ou um objeto de falha, quando só essa métrica falhou.",
                        "anyOf": [
                          {
                            "$ref": "#/components/schemas/MetricFailure"
                          },
                          {
                            "description": "O resultado da métrica, no formato do `component`."
                          }
                        ]
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "f35a44ce-dac5-4188-aace-5c44a8952176": {
                      "value": 128,
                      "previous_value": 96
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A coleta falhou. Esta API embrulha qualquer falha inesperada aqui, então a mensagem é o único detalhe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Unexpected response from API, please try again"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Validação. **Dois envelopes possíveis aqui**, e são diferentes: as regras do corpo devolvem `errors`, e as recusas de acesso à métrica ou de token expirado devolvem `message` com `extra`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/FormValidationError"
                    },
                    {
                      "$ref": "#/components/schemas/MetricsValidationError"
                    }
                  ]
                },
                "examples": {
                  "corpo_invalido": {
                    "value": {
                      "errors": {
                        "start": [
                          "The start field is required."
                        ]
                      }
                    }
                  },
                  "token_da_conexao_expirado": {
                    "summary": "A conexão precisa ser reautorizada pelo cliente",
                    "value": {
                      "message": "Customer integration needs to be reintegrated, token is invalid or expired",
                      "extra": {
                        "integration_status": "expired"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/metrics/get-data-async": {
      "post": {
        "tags": [
          "Metrics"
        ],
        "operationId": "getMetricsAsync",
        "summary": "Pede as métricas e recebe por webhook",
        "description": "Responde imediatamente e entrega as métricas depois, num `POST` para o `metrics_webhook_url`. É o caminho recomendado para períodos longos.\n\nO corpo entregue no seu webhook é o mapa de métricas na raiz, **sem** o envelope `data` que a versão síncrona usa.\n\nA URL do webhook é validada contra endereços de rede internos, então precisa ser publicamente alcançável.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/MetricsRequest"
                  },
                  {
                    "type": "object",
                    "required": [
                      "metrics_webhook_url"
                    ],
                    "properties": {
                      "metrics_webhook_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Precisa ser http ou https e apontar para um endereço público. IPs privados, loopback e link-local são recusados."
                      }
                    }
                  }
                ]
              },
              "example": {
                "metrics_webhook_url": "https://sua-aplicacao.com/webhooks/metricas",
                "customer_integration": "4addc0da-8583-4dbb-a0e9-c7e2e8470f50",
                "start": "2026-08-01",
                "end": "2026-08-31",
                "metrics": [
                  {
                    "id": "f35a44ce-dac5-4188-aace-5c44a8952176",
                    "reference_key": "ig:story_replies",
                    "component": "number_v1",
                    "metrics": [
                      "replies"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aceito. As métricas chegam no webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessage"
                },
                "example": {
                  "success": true,
                  "message": "Metrics will be sent to your webhook"
                }
              }
            }
          },
          "400": {
            "description": "A coleta falhou",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Validação",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/FormValidationError"
                    },
                    {
                      "$ref": "#/components/schemas/MetricsValidationError"
                    }
                  ]
                },
                "example": {
                  "errors": {
                    "metrics_webhook_url": [
                      "The metrics webhook url points to a restricted network address."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/options": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAdsOptions",
        "summary": "O vocabulário de uma integração de anúncios",
        "description": "O que a integração aceita, nível a nível: os valores dos campos comuns e o bloco que só ela conhece. Não depende de conexão.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "name": "integration_slug",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "facebook_ads"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "O vocabulário",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdsOptions"
                },
                "example": {
                  "data": {
                    "integration_slug": "facebook_ads",
                    "budget": {
                      "levels": [
                        "campaign",
                        "adset"
                      ],
                      "types": [
                        "daily",
                        "lifetime"
                      ]
                    },
                    "common": {
                      "format": [
                        "image",
                        "video"
                      ]
                    },
                    "facebook_ads": {
                      "campaign": {
                        "objective": [
                          "traffic"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/campaigns": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsCampaigns",
        "summary": "Lista as campanhas",
        "description": "Lê do banco do Connect por padrão (`source=connect`): o que o Connect criou ou já escreveu nesta conta, como o `GET /posts`. Com `source=external`, lê a conta ao vivo.\n\n`include_deleted` só existe com `source=connect`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Com `source=connect`, filtra pelo último status conhecido. Com `source=external`, pelo status atual, e a página pode trazer um pouco mais que `per_page`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused"
              ]
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "required": false,
            "description": "Inclui os apagados, com `deleted_at`.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/AdsPerPage"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista as campanhas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "links",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdsCampaign"
                      }
                    },
                    "links": {
                      "$ref": "#/components/schemas/AdsPageLinks"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/AdsPageMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "120250000000000001",
                      "uuid": "9a1d3f52-7c1e-4c55-9b0e-5c3f1c6a2e10",
                      "origin": "created",
                      "synced_at": "2026-11-19T10:00:00-03:00",
                      "deleted_at": null,
                      "name": "Black Friday",
                      "status": "paused",
                      "effective_status": "paused",
                      "budget": {
                        "amount": 50,
                        "type": "daily",
                        "level": "campaign",
                        "currency": "BRL"
                      },
                      "adsets_count": 1,
                      "facebook_ads": {
                        "objective": "traffic",
                        "spend_cap": null,
                        "bid_strategy": "lowest_cost"
                      },
                      "created_at": "2026-11-19T10:00:00-0300",
                      "updated_at": "2026-11-19T10:00:00-0300"
                    }
                  ],
                  "links": {
                    "first": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "last": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "prev": null,
                    "next": null
                  },
                  "meta": {
                    "current_page": 1,
                    "from": 1,
                    "last_page": 1,
                    "path": "https://connect.reportei.com/api/ads/campaigns",
                    "per_page": 15,
                    "to": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "createAdsCampaign",
        "summary": "Cria uma campanha",
        "description": "Nasce **pausada** sem `status`. Com `budget`, o orçamento fica na campanha (CBO); sem, fica em cada conjunto (ABO).",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsCampaignInput"
              },
              "example": {
                "name": "Black Friday",
                "budget": {
                  "amount": 50,
                  "type": "daily"
                },
                "facebook_ads": {
                  "objective": "traffic",
                  "special_ad_categories": []
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cria uma campanha",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsCampaign"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "uuid": "9a1d3f52-7c1e-4c55-9b0e-5c3f1c6a2e10",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "name": "Black Friday",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": {
                      "amount": 50,
                      "type": "daily",
                      "level": "campaign",
                      "currency": "BRL"
                    },
                    "adsets_count": 1,
                    "facebook_ads": {
                      "objective": "traffic",
                      "spend_cap": null,
                      "bid_strategy": "lowest_cost"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido: o corpo da primeira resposta, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsCampaign"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "uuid": "9a1d3f52-7c1e-4c55-9b0e-5c3f1c6a2e10",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "name": "Black Friday",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": {
                      "amount": 50,
                      "type": "daily",
                      "level": "campaign",
                      "currency": "BRL"
                    },
                    "adsets_count": 1,
                    "facebook_ads": {
                      "objective": "traffic",
                      "spend_cap": null,
                      "bid_strategy": "lowest_cost"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/campaigns/{id}": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAdsCampaign",
        "summary": "Uma campanha",
        "description": "Do banco do Connect por padrão; com `source=external`, ao vivo. Com `source=connect`, um objeto que o Connect não guarda responde 404.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Uma campanha",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsCampaign"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "uuid": "9a1d3f52-7c1e-4c55-9b0e-5c3f1c6a2e10",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "name": "Black Friday",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": {
                      "amount": 50,
                      "type": "daily",
                      "level": "campaign",
                      "currency": "BRL"
                    },
                    "adsets_count": 1,
                    "facebook_ads": {
                      "objective": "traffic",
                      "spend_cap": null,
                      "bid_strategy": "lowest_cost"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Ads"
        ],
        "operationId": "updateAdsCampaign",
        "summary": "Atualiza uma campanha",
        "description": "Vale para qualquer campanha da conta. Uma criada fora do Connect entra no banco nesta escrita (`origin: imported`). Orçamento numa campanha ABO responde `409 budget_level_mismatch`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsCampaignUpdate"
              },
              "example": {
                "status": "active"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualiza uma campanha",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsCampaign"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "uuid": "9a1d3f52-7c1e-4c55-9b0e-5c3f1c6a2e10",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "name": "Black Friday",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": {
                      "amount": 50,
                      "type": "daily",
                      "level": "campaign",
                      "currency": "BRL"
                    },
                    "adsets_count": 1,
                    "facebook_ads": {
                      "objective": "traffic",
                      "spend_cap": null,
                      "bid_strategy": "lowest_cost"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Ads"
        ],
        "operationId": "deleteAdsCampaign",
        "summary": "Apaga uma campanha",
        "description": "Leva junto os conjuntos e anúncios dela, na integração e no banco do Connect.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Apaga uma campanha",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdsDeleted"
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "deleted": true
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/adsets": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsAdsets",
        "summary": "Lista os conjuntos",
        "description": "Lê do banco do Connect por padrão (`source=connect`): o que o Connect criou ou já escreveu nesta conta, como o `GET /posts`. Com `source=external`, lê a conta ao vivo.\n\n`include_deleted` só existe com `source=connect`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Com `source=connect`, filtra pelo último status conhecido. Com `source=external`, pelo status atual, e a página pode trazer um pouco mais que `per_page`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused"
              ]
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "O `id` da campanha ou o `uuid` do Connect.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "required": false,
            "description": "Inclui os apagados, com `deleted_at`.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/AdsPerPage"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista os conjuntos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "links",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdsAdset"
                      }
                    },
                    "links": {
                      "$ref": "#/components/schemas/AdsPageLinks"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/AdsPageMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "120250000000000002",
                      "uuid": "1b2c3d4e-5f60-4718-8a9b-0c1d2e3f4a5b",
                      "origin": "created",
                      "synced_at": "2026-11-19T10:00:00-03:00",
                      "deleted_at": null,
                      "campaign_id": "120250000000000001",
                      "name": "BR 25-45",
                      "status": "paused",
                      "effective_status": "paused",
                      "budget": null,
                      "schedule": {
                        "start": "2026-11-20T00:00:00-0300",
                        "end": null
                      },
                      "targeting": {
                        "countries": [
                          "BR"
                        ],
                        "age_min": 25,
                        "age_max": 45,
                        "genders": [
                          "all"
                        ]
                      },
                      "facebook_ads": {
                        "optimization_goal": "link_clicks",
                        "billing_event": "impressions",
                        "bid_strategy": null,
                        "bid_amount": null,
                        "placements": {},
                        "targeting": {
                          "interests": [],
                          "custom_audiences": [],
                          "excluded_custom_audiences": [],
                          "advantage_audience": false,
                          "raw": {}
                        }
                      },
                      "created_at": "2026-11-19T10:00:00-0300",
                      "updated_at": "2026-11-19T10:00:00-0300"
                    }
                  ],
                  "links": {
                    "first": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "last": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "prev": null,
                    "next": null
                  },
                  "meta": {
                    "current_page": 1,
                    "from": 1,
                    "last_page": 1,
                    "path": "https://connect.reportei.com/api/ads/campaigns",
                    "per_page": 15,
                    "to": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "createAdsAdset",
        "summary": "Cria um conjunto",
        "description": "Numa campanha existente. Nasce **pausado** sem `status`. Orçamento num conjunto de campanha CBO responde `409 budget_level_mismatch`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsAdsetInput"
              },
              "example": {
                "campaign_id": "120250000000000001",
                "name": "BR 25-45",
                "budget": {
                  "amount": 20,
                  "type": "daily"
                },
                "targeting": {
                  "countries": [
                    "BR"
                  ]
                },
                "facebook_ads": {
                  "optimization_goal": "link_clicks",
                  "billing_event": "impressions"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cria um conjunto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAdset"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000002",
                    "uuid": "1b2c3d4e-5f60-4718-8a9b-0c1d2e3f4a5b",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "name": "BR 25-45",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": null,
                    "schedule": {
                      "start": "2026-11-20T00:00:00-0300",
                      "end": null
                    },
                    "targeting": {
                      "countries": [
                        "BR"
                      ],
                      "age_min": 25,
                      "age_max": 45,
                      "genders": [
                        "all"
                      ]
                    },
                    "facebook_ads": {
                      "optimization_goal": "link_clicks",
                      "billing_event": "impressions",
                      "bid_strategy": null,
                      "bid_amount": null,
                      "placements": {},
                      "targeting": {
                        "interests": [],
                        "custom_audiences": [],
                        "excluded_custom_audiences": [],
                        "advantage_audience": false,
                        "raw": {}
                      }
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido: o corpo da primeira resposta, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAdset"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000002",
                    "uuid": "1b2c3d4e-5f60-4718-8a9b-0c1d2e3f4a5b",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "name": "BR 25-45",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": null,
                    "schedule": {
                      "start": "2026-11-20T00:00:00-0300",
                      "end": null
                    },
                    "targeting": {
                      "countries": [
                        "BR"
                      ],
                      "age_min": 25,
                      "age_max": 45,
                      "genders": [
                        "all"
                      ]
                    },
                    "facebook_ads": {
                      "optimization_goal": "link_clicks",
                      "billing_event": "impressions",
                      "bid_strategy": null,
                      "bid_amount": null,
                      "placements": {},
                      "targeting": {
                        "interests": [],
                        "custom_audiences": [],
                        "excluded_custom_audiences": [],
                        "advantage_audience": false,
                        "raw": {}
                      }
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/adsets/{id}": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAdsAdset",
        "summary": "Um conjunto",
        "description": "Do banco do Connect por padrão; com `source=external`, ao vivo. Com `source=connect`, um objeto que o Connect não guarda responde 404.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Um conjunto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAdset"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000002",
                    "uuid": "1b2c3d4e-5f60-4718-8a9b-0c1d2e3f4a5b",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "name": "BR 25-45",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": null,
                    "schedule": {
                      "start": "2026-11-20T00:00:00-0300",
                      "end": null
                    },
                    "targeting": {
                      "countries": [
                        "BR"
                      ],
                      "age_min": 25,
                      "age_max": 45,
                      "genders": [
                        "all"
                      ]
                    },
                    "facebook_ads": {
                      "optimization_goal": "link_clicks",
                      "billing_event": "impressions",
                      "bid_strategy": null,
                      "bid_amount": null,
                      "placements": {},
                      "targeting": {
                        "interests": [],
                        "custom_audiences": [],
                        "excluded_custom_audiences": [],
                        "advantage_audience": false,
                        "raw": {}
                      }
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Ads"
        ],
        "operationId": "updateAdsAdset",
        "summary": "Atualiza um conjunto",
        "description": "Vale para qualquer conjunto da conta. Orçamento num conjunto de campanha CBO responde `409 budget_level_mismatch`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsAdsetUpdate"
              },
              "example": {
                "targeting": {
                  "age_min": 30
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualiza um conjunto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAdset"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000002",
                    "uuid": "1b2c3d4e-5f60-4718-8a9b-0c1d2e3f4a5b",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "name": "BR 25-45",
                    "status": "paused",
                    "effective_status": "paused",
                    "budget": null,
                    "schedule": {
                      "start": "2026-11-20T00:00:00-0300",
                      "end": null
                    },
                    "targeting": {
                      "countries": [
                        "BR"
                      ],
                      "age_min": 25,
                      "age_max": 45,
                      "genders": [
                        "all"
                      ]
                    },
                    "facebook_ads": {
                      "optimization_goal": "link_clicks",
                      "billing_event": "impressions",
                      "bid_strategy": null,
                      "bid_amount": null,
                      "placements": {},
                      "targeting": {
                        "interests": [],
                        "custom_audiences": [],
                        "excluded_custom_audiences": [],
                        "advantage_audience": false,
                        "raw": {}
                      }
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Ads"
        ],
        "operationId": "deleteAdsAdset",
        "summary": "Apaga um conjunto",
        "description": "Leva junto os anúncios dele.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Apaga um conjunto",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdsDeleted"
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "deleted": true
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAds",
        "summary": "Lista os anúncios",
        "description": "Lê do banco do Connect por padrão (`source=connect`): o que o Connect criou ou já escreveu nesta conta, como o `GET /posts`. Com `source=external`, lê a conta ao vivo.\n\n`include_deleted` só existe com `source=connect`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Com `source=connect`, filtra pelo último status conhecido. Com `source=external`, pelo status atual, e a página pode trazer um pouco mais que `per_page`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused"
              ]
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "O `id` da campanha ou o `uuid` do Connect.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "adset_id",
            "in": "query",
            "required": false,
            "description": "O `id` do conjunto ou o `uuid` do Connect.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "required": false,
            "description": "Inclui os apagados, com `deleted_at`.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/AdsPerPage"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista os anúncios",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "links",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdsAd"
                      }
                    },
                    "links": {
                      "$ref": "#/components/schemas/AdsPageLinks"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/AdsPageMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "120250000000000003",
                      "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                      "origin": "created",
                      "synced_at": "2026-11-19T10:00:00-03:00",
                      "deleted_at": null,
                      "campaign_id": "120250000000000001",
                      "adset_id": "120250000000000002",
                      "name": "Black Friday, imagem",
                      "status": "active",
                      "effective_status": "pending_review",
                      "format": "image",
                      "headline": "Black Friday",
                      "body": "Até 50% off",
                      "description": null,
                      "link_url": "https://loja.com/bf",
                      "call_to_action": "shop_now",
                      "thumbnail_url": null,
                      "facebook_ads": {
                        "creative_id": "120250000000000004",
                        "page_id": "1068595869664481",
                        "instagram_account_id": null,
                        "post_id": null
                      },
                      "created_at": "2026-11-19T10:00:00-0300",
                      "updated_at": "2026-11-19T10:00:00-0300"
                    }
                  ],
                  "links": {
                    "first": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "last": "https://connect.reportei.com/api/ads/campaigns?page=1",
                    "prev": null,
                    "next": null
                  },
                  "meta": {
                    "current_page": 1,
                    "from": 1,
                    "last_page": 1,
                    "path": "https://connect.reportei.com/api/ads/campaigns",
                    "per_page": 15,
                    "to": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "createAds",
        "summary": "Cria um anúncio e a árvore acima dele",
        "description": "Uma forma só: cada nível usa um existente (`{\"id\": …}`) ou descreve o que será criado.\n\n- **Tudo nasce pausado.** O `status` pedido é aplicado no último passo, então uma falha no meio nunca deixa nada gastando.\n- **Cada id é gravado assim que a integração responde.** Um retry com a mesma `Idempotency-Key` retoma de onde parou.\n- **Falha:** o que foi criado é desfeito; o que não pôde ser vem em `created`.\n- **Vídeo ainda processando:** `409 ads_video_not_ready`. Repita com a mesma chave: o vídeo e os níveis já criados são reaproveitados.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsTreeRequest"
              },
              "example": {
                "name": "Black Friday, imagem",
                "status": "active",
                "campaign": {
                  "name": "Black Friday",
                  "budget": {
                    "amount": 50,
                    "type": "daily"
                  },
                  "facebook_ads": {
                    "objective": "traffic",
                    "special_ad_categories": []
                  }
                },
                "adset": {
                  "name": "BR 25-45",
                  "schedule": {
                    "start": "2026-11-20T00:00:00-03:00"
                  },
                  "targeting": {
                    "countries": [
                      "BR"
                    ],
                    "age_min": 25,
                    "age_max": 45
                  },
                  "facebook_ads": {
                    "optimization_goal": "link_clicks",
                    "billing_event": "impressions",
                    "placements": {
                      "publisher_platforms": [
                        "facebook",
                        "instagram"
                      ]
                    },
                    "targeting": {
                      "interests": [
                        {
                          "id": "6003139266461",
                          "name": "Moda"
                        }
                      ],
                      "advantage_audience": false
                    }
                  }
                },
                "ad": {
                  "format": "image",
                  "headline": "Black Friday",
                  "body": "Até 50% off",
                  "link_url": "https://loja.com/bf",
                  "call_to_action": "shop_now",
                  "media": [
                    {
                      "type": "image",
                      "url": "https://cdn.loja.com/bf.jpg"
                    }
                  ],
                  "facebook_ads": {
                    "page_id": "1068595869664481"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cria um anúncio e a árvore acima dele",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido: o corpo da primeira resposta, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/boost": {
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "boostAdsPost",
        "summary": "Impulsiona um post",
        "description": "A mesma árvore do `POST /ads`, com um anúncio que promove um post existente. O criativo vem do post.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsBoostRequest"
              },
              "example": {
                "name": "Impulsionar post",
                "status": "active",
                "campaign": {
                  "facebook_ads": {
                    "objective": "engagement"
                  }
                },
                "adset": {
                  "budget": {
                    "amount": 20,
                    "type": "daily"
                  },
                  "targeting": {
                    "countries": [
                      "BR"
                    ]
                  },
                  "facebook_ads": {
                    "optimization_goal": "post_engagement",
                    "billing_event": "impressions"
                  }
                },
                "ad": {
                  "post_id": "18191649508387596",
                  "facebook_ads": {
                    "instagram_account_id": "17841442920331135"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Impulsiona um post",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "post",
                    "headline": null,
                    "body": null,
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": null,
                      "instagram_account_id": "17841442920331135",
                      "post_id": "18191649508387596"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido: o corpo da primeira resposta, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "post",
                    "headline": null,
                    "body": null,
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": null,
                      "instagram_account_id": "17841442920331135",
                      "post_id": "18191649508387596"
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/validate": {
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "validateAds",
        "summary": "Valida a árvore sem criar nada",
        "description": "O mesmo corpo do `POST /ads`. A integração valida cada nível; os que dependem de um pai ainda inexistente voltam `skipped`. Não registra operação e não precisa de `Idempotency-Key`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsTreeRequest"
              },
              "example": {
                "name": "Black Friday, imagem",
                "status": "active",
                "campaign": {
                  "name": "Black Friday",
                  "budget": {
                    "amount": 50,
                    "type": "daily"
                  },
                  "facebook_ads": {
                    "objective": "traffic",
                    "special_ad_categories": []
                  }
                },
                "adset": {
                  "name": "BR 25-45",
                  "schedule": {
                    "start": "2026-11-20T00:00:00-03:00"
                  },
                  "targeting": {
                    "countries": [
                      "BR"
                    ],
                    "age_min": 25,
                    "age_max": 45
                  },
                  "facebook_ads": {
                    "optimization_goal": "link_clicks",
                    "billing_event": "impressions",
                    "placements": {
                      "publisher_platforms": [
                        "facebook",
                        "instagram"
                      ]
                    },
                    "targeting": {
                      "interests": [
                        {
                          "id": "6003139266461",
                          "name": "Moda"
                        }
                      ],
                      "advantage_audience": false
                    }
                  }
                },
                "ad": {
                  "format": "image",
                  "headline": "Black Friday",
                  "body": "Até 50% off",
                  "link_url": "https://loja.com/bf",
                  "call_to_action": "shop_now",
                  "media": [
                    {
                      "type": "image",
                      "url": "https://cdn.loja.com/bf.jpg"
                    }
                  ],
                  "facebook_ads": {
                    "page_id": "1068595869664481"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "O resultado por nível",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdsValidation"
                },
                "example": {
                  "data": {
                    "results": [
                      {
                        "level": "campaign",
                        "status": "validated"
                      },
                      {
                        "level": "adset",
                        "status": "skipped"
                      },
                      {
                        "level": "ad",
                        "status": "skipped"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/{id}": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAd",
        "summary": "Um anúncio",
        "description": "Do banco do Connect por padrão; com `source=external`, ao vivo. Com `source=connect`, um objeto que o Connect não guarda responde 404.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsSource"
          },
          {
            "$ref": "#/components/parameters/AdsRefresh"
          }
        ],
        "responses": {
          "200": {
            "description": "Um anúncio",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Ads"
        ],
        "operationId": "updateAd",
        "summary": "Atualiza um anúncio",
        "description": "Nome, status e textos. Um anúncio impulsionado não troca de criativo (`boosted_creative_not_replaceable`).",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsAdUpdate"
              },
              "example": {
                "status": "paused"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualiza um anúncio",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "active",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Ads"
        ],
        "operationId": "deleteAd",
        "summary": "Apaga um anúncio",
        "description": "O conjunto e a campanha continuam.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Apaga um anúncio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdsDeleted"
                },
                "example": {
                  "data": {
                    "id": "120250000000000001",
                    "deleted": true
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/{id}/duplicate": {
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "duplicateAd",
        "summary": "Duplica um anúncio",
        "description": "A cópia nasce sempre pausada, no mesmo conjunto.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsObjectId"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdsDuplicateRequest"
              },
              "example": {
                "name": "Black Friday, cópia"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Duplica um anúncio",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "paused",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido: o corpo da primeira resposta, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdsAd"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "120250000000000003",
                    "uuid": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                    "origin": "created",
                    "synced_at": "2026-11-19T10:00:00-03:00",
                    "deleted_at": null,
                    "campaign_id": "120250000000000001",
                    "adset_id": "120250000000000002",
                    "name": "Black Friday, imagem",
                    "status": "paused",
                    "effective_status": "pending_review",
                    "format": "image",
                    "headline": "Black Friday",
                    "body": "Até 50% off",
                    "description": null,
                    "link_url": "https://loja.com/bf",
                    "call_to_action": "shop_now",
                    "thumbnail_url": null,
                    "facebook_ads": {
                      "creative_id": "120250000000000004",
                      "page_id": "1068595869664481",
                      "instagram_account_id": null,
                      "post_id": null
                    },
                    "created_at": "2026-11-19T10:00:00-0300",
                    "updated_at": "2026-11-19T10:00:00-0300"
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          }
        }
      }
    },
    "/ads/facebook_ads/pages": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsPages",
        "summary": "As páginas que a conexão administra",
        "description": "Cada página traz a conta do Instagram ligada a ela, que é o que um anúncio precisa para publicar pelos dois.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As páginas que a conexão administra",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Page"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "1068595869664481",
                      "name": "Reportei Sync",
                      "picture_url": "https://cdn.meta/p.png",
                      "can_post": true,
                      "instagram_account_id": "17841442920331135"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/facebook_ads/instagram-accounts": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsInstagramAccounts",
        "summary": "As contas do Instagram da conta de anúncios",
        "description": "As contas que esta conta de anúncios pode usar para publicar.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As contas do Instagram da conta de anúncios",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InstagramAccount"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "17841442920331135",
                      "username": "reporteisync"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/facebook_ads/posts": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsPosts",
        "summary": "O conteúdo orgânico que pode ser impulsionado",
        "description": "Sem `source`, lista a **mídia do Instagram**, a única que `creative.source_post_id` aceita. Com `source=facebook`, lista os posts da página, que servem para descoberta mas não para impulsionar.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Padrão `instagram`.",
            "schema": {
              "type": "string",
              "enum": [
                "instagram",
                "facebook"
              ],
              "default": "instagram"
            }
          },
          {
            "name": "instagram_account_id",
            "in": "query",
            "required": false,
            "description": "Obrigatório com `source=instagram`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page_id",
            "in": "query",
            "required": false,
            "description": "Obrigatório com `source=facebook`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "O conteúdo orgânico que pode ser impulsionado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Post"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "18191649508387596",
                      "source": "instagram",
                      "type": "image",
                      "caption": "Legenda do post",
                      "permalink": "https://instagram.com/p/x",
                      "thumbnail_url": "https://cdn.ig/a.jpg",
                      "published_at": "2026-08-19T18:47:47+0000"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/facebook_ads/pixels": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsPixels",
        "summary": "Os pixels da conta de anúncios",
        "description": "O `id` de um pixel vai em `adset.facebook_ads.promoted_object.pixel_id` de um conjunto otimizado para conversão.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Os pixels da conta de anúncios",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Pixel"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "900000000000001",
                      "name": "Pixel principal",
                      "last_fired_at": "2026-09-23T10:00:00-0300",
                      "created_at": "2025-01-01T00:00:00-0300",
                      "is_unavailable": false
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/facebook_ads/pixels/{id}/events": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsPixelEvents",
        "summary": "Os eventos que um pixel registrou",
        "description": "Contagem dos últimos **90 dias**, janela que a integração usa para que evento raro não suma.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "O id do pixel.",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Os eventos que um pixel registrou",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PixelEvent"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "event_name": "Purchase",
                      "count": 42
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/facebook_ads/custom-conversions": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsCustomConversions",
        "summary": "As conversões personalizadas da conta",
        "description": "O `id` de uma conversão vai em `adset.facebook_ads.promoted_object.custom_conversion_id`.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As conversões personalizadas da conta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomConversion"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "700000000000001",
                      "name": "Compra concluída",
                      "event_type": "other",
                      "pixel_id": "900000000000001",
                      "is_unavailable": false
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "createAdsCustomConversion",
        "summary": "Cria uma conversão personalizada",
        "description": "Define uma conversão personalizada pela regra que a dispara. A conversão criada aparece na listagem seguinte sem `refresh`.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomConversionCreateRequest"
              },
              "example": {
                "name": "Compra concluída",
                "pixel_id": "900000000000001",
                "rule": {
                  "url_contains": "/obrigado"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A conversão criada",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CustomConversion"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "700000000000001",
                    "name": "Compra concluída",
                    "event_type": "other",
                    "pixel_id": "900000000000001",
                    "is_unavailable": false
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "A repetição guardada de uma chamada anterior com a mesma `Idempotency-Key` e o mesmo pedido, com `Idempotent-Replay: true`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CustomConversion"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "700000000000001",
                    "name": "Compra concluída",
                    "event_type": "other",
                    "pixel_id": "900000000000001",
                    "is_unavailable": false
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replay": {
                "description": "`true` quando a resposta é a repetição guardada de uma chamada anterior com a mesma `Idempotency-Key`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/AdsConflict"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "$ref": "#/components/parameters/AdsIdempotencyKeyRequired"
          }
        ]
      }
    },
    "/ads/audiences": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listAdsAudiences",
        "summary": "Os públicos personalizados da conta",
        "description": "Somente leitura. Criar público e subir lista de usuários não faz parte desta versão.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Os públicos personalizados da conta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Audience"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "800000000000001",
                      "name": "Compradores 90 dias",
                      "subtype": "custom",
                      "approximate_size": {
                        "lower": 1000,
                        "upper": 2000
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/ads/targeting/search": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "searchAdsTargeting",
        "summary": "Busca interesses, lugares e comportamentos",
        "description": "Resolve um termo nos ids que a segmentação espera. **É o que tira `targeting.interests` de \"o merchant já tem que saber o id\".**\n\n`behavior` navega a lista inteira sem `q`; `interest` e `geo` exigem o termo.\n\nLeitura com cache de 600 s por conexão. **Não pagina:** a integração devolve no máximo 200 itens por recurso.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdsCustomerIntegration"
          },
          {
            "name": "type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "interest",
                "geo",
                "behavior"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Obrigatório para `interest` e `geo`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "country_code",
            "in": "query",
            "required": false,
            "description": "Só tem efeito em `geo`.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2,
              "pattern": "^[A-Za-z]{2}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Ignora o cache e busca na integração.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Busca interesses, lugares e comportamentos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TargetingResult"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/DiscoveryListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "6003279598823",
                      "name": "Marketing (negócios e finanças)",
                      "type": "interest",
                      "subtype": null,
                      "path": [
                        "Interesses",
                        "Marketing (negócios e finanças)"
                      ],
                      "description": null,
                      "country_code": null,
                      "audience_size": {
                        "lower": 605494039,
                        "upper": 712060990
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/CustomerAccessError"
          },
          "403": {
            "$ref": "#/components/responses/AdsForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AdsObjectNotFound"
          },
          "422": {
            "$ref": "#/components/responses/AdsValidationError"
          },
          "4XX": {
            "$ref": "#/components/responses/AdsIntegrationRefused"
          },
          "5XX": {
            "$ref": "#/components/responses/AdsIntegrationUnavailable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhook-subscriptions": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "listWebhookSubscriptions",
        "summary": "Lista seus webhooks",
        "description": "Os endereços que a sua conta registrou para receber eventos. Um webhook é da conta, não do cliente: um só endereço recebe os eventos de todos os seus clientes.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 15
            },
            "description": "Quantos por página."
          }
        ],
        "responses": {
          "200": {
            "description": "A lista, paginada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookSubscription"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "createWebhookSubscription",
        "summary": "Registra um webhook",
        "description": "Passa a entregar os eventos escolhidos no endereço informado. A entrega é assinada: confira a assinatura antes de confiar no corpo.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "events"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "Endereço `https` que vai receber os eventos. Recusamos endereços internos ou de rede privada, e o mesmo endereço não pode ser registrado duas vezes na mesma conta."
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "customer_integration.status_updated",
                        "customer_integration.deleted",
                        "oauth_started",
                        "oauth_saved",
                        "session_completed"
                      ]
                    },
                    "description": "Quais eventos este endereço recebe."
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true,
                    "description": "Um registro inativo continua existindo e para de receber."
                  }
                }
              },
              "example": {
                "url": "https://sua-app.com/webhooks/connect",
                "events": [
                  "customer_integration.status_updated",
                  "session_completed"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registrado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_subscription": {
                      "$ref": "#/components/schemas/WebhookSubscription"
                    }
                  }
                },
                "example": {
                  "webhook_subscription": {
                    "id": 12,
                    "url": "https://sua-app.com/webhooks/connect",
                    "events": [
                      "customer_integration.status_updated",
                      "session_completed"
                    ],
                    "is_active": true,
                    "created_at": "2026-09-01T12:00:00.000000Z",
                    "updated_at": "2026-09-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhook-subscriptions/{id}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "getWebhookSubscription",
        "summary": "Detalha um webhook",
        "description": "Um registro da sua conta.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "O id do registro, como devolvido na criação."
          }
        ],
        "responses": {
          "200": {
            "description": "O registro.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_subscription": {
                      "$ref": "#/components/schemas/WebhookSubscription"
                    }
                  }
                },
                "example": {
                  "webhook_subscription": {
                    "id": 12,
                    "url": "https://sua-app.com/webhooks/connect",
                    "events": [
                      "customer_integration.status_updated",
                      "session_completed"
                    ],
                    "is_active": true,
                    "created_at": "2026-09-01T12:00:00.000000Z",
                    "updated_at": "2026-09-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "description": "Não existe, ou não é da sua conta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Not Found"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "updateWebhookSubscription",
        "summary": "Atualiza um webhook",
        "description": "Manda só o que muda. `PATCH` faz o mesmo.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "O id do registro, como devolvido na criação."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "Endereço `https` que vai receber os eventos. Recusamos endereços internos ou de rede privada, e o mesmo endereço não pode ser registrado duas vezes na mesma conta."
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "customer_integration.status_updated",
                        "customer_integration.deleted",
                        "oauth_started",
                        "oauth_saved",
                        "session_completed"
                      ]
                    },
                    "description": "Quais eventos este endereço recebe."
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true,
                    "description": "Um registro inativo continua existindo e para de receber."
                  }
                }
              },
              "example": {
                "is_active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_subscription": {
                      "$ref": "#/components/schemas/WebhookSubscription"
                    }
                  }
                },
                "example": {
                  "webhook_subscription": {
                    "id": 12,
                    "url": "https://sua-app.com/webhooks/connect",
                    "events": [
                      "customer_integration.status_updated",
                      "session_completed"
                    ],
                    "is_active": true,
                    "created_at": "2026-09-01T12:00:00.000000Z",
                    "updated_at": "2026-09-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "description": "Não existe, ou não é da sua conta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Not Found"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "patchWebhookSubscription",
        "summary": "Atualiza um webhook",
        "description": "Idêntico ao `PUT` desta mesma rota.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "O id do registro, como devolvido na criação."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "Endereço `https` que vai receber os eventos. Recusamos endereços internos ou de rede privada, e o mesmo endereço não pode ser registrado duas vezes na mesma conta."
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "customer_integration.status_updated",
                        "customer_integration.deleted",
                        "oauth_started",
                        "oauth_saved",
                        "session_completed"
                      ]
                    },
                    "description": "Quais eventos este endereço recebe."
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true,
                    "description": "Um registro inativo continua existindo e para de receber."
                  }
                }
              },
              "example": {
                "is_active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_subscription": {
                      "$ref": "#/components/schemas/WebhookSubscription"
                    }
                  }
                },
                "example": {
                  "webhook_subscription": {
                    "id": 12,
                    "url": "https://sua-app.com/webhooks/connect",
                    "events": [
                      "customer_integration.status_updated",
                      "session_completed"
                    ],
                    "is_active": true,
                    "created_at": "2026-09-01T12:00:00.000000Z",
                    "updated_at": "2026-09-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "description": "Não existe, ou não é da sua conta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Not Found"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "deleteWebhookSubscription",
        "summary": "Remove um webhook",
        "description": "Para de entregar nesse endereço. Os eventos já entregues não são afetados.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "O id do registro, como devolvido na criação."
          }
        ],
        "responses": {
          "200": {
            "description": "Removido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessage"
                },
                "example": {
                  "success": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "description": "Falha de validação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "url": [
                      "This webhook URL is already registered for your account."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "description": "Não existe, ou não é da sua conta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Not Found"
                }
              }
            }
          }
        }
      }
    },
    "/customers/integrations": {
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "listCustomersWithIntegrations",
        "summary": "Lista seus clientes com as conexões de cada um",
        "description": "A mesma lista de `GET /customers`, com as conexões embutidas. Evita uma chamada por cliente quando você só quer um panorama.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Filtra por nome do cliente."
          }
        ],
        "responses": {
          "200": {
            "description": "Os clientes e suas conexões.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerWithIntegrations"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customer-integrations/{uuid}/update-status": {
      "post": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "updateCustomerIntegrationStatus",
        "summary": "Muda o status de uma conexão",
        "description": "Marca a conexão como ativa, expirada ou revogada. Serve para refletir no Connect algo que você já sabe, por exemplo, que o seu cliente desautorizou o acesso do lado da rede.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "O `uuid` da conexão."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "$ref": "#/components/schemas/IntegrationStatus"
                  }
                }
              },
              "example": {
                "status": "revoked"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "old_status",
                    "new_status",
                    "message"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "old_status": {
                      "$ref": "#/components/schemas/IntegrationStatus"
                    },
                    "new_status": {
                      "$ref": "#/components/schemas/IntegrationStatus"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "old_status": "active",
                  "new_status": "revoked",
                  "message": "Integration with id '2c94ccbe-54dd-4a28-8099-a2b248204329', 'Minha Página' status updated to 'revoked'"
                }
              }
            }
          },
          "400": {
            "description": "A mudança não foi aplicada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageError"
                },
                "example": {
                  "message": "Integration not found"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Status fora do vocabulário, ou conexão inexistente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "status": [
                      "The selected status is invalid."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customer-integrations/session-shared": {
      "post": {
        "tags": [
          "Customer Integrations"
        ],
        "operationId": "createSharedIntegrationSession",
        "summary": "Cria uma sessão de integração compartilhada",
        "description": "Variante de `POST /customer-integrations/session` para quando **a mesma conta de origem** vai ser ligada a vários clientes seus de uma vez. Em vez de uma sessão por cliente, você lista os pares cliente + id de origem e recebe um só link.",
        "security": [
          {
            "bearerAuth": [],
            "customerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "redirect_url",
                  "source_slug",
                  "source_ids"
                ],
                "properties": {
                  "redirect_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Para onde o seu cliente volta ao terminar."
                  },
                  "source_slug": {
                    "type": "string",
                    "description": "O slug da integração, como em `GET /merchants/settings`."
                  },
                  "source_ids": {
                    "type": "array",
                    "minItems": 1,
                    "description": "Um par por cliente seu.",
                    "items": {
                      "type": "object",
                      "required": [
                        "customer_uuid",
                        "source_id"
                      ],
                      "properties": {
                        "customer_uuid": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "source_id": {
                          "type": "string",
                          "description": "O id da conta de origem a ligar a esse cliente."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "redirect_url": "https://sua-app.com/integracoes/pronto",
                "source_slug": "facebook_ads",
                "source_ids": [
                  {
                    "customer_uuid": "0d835ce8-d0a3-4763-a2ec-d01a605ac404",
                    "source_id": "act_1884348095855063"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A sessão, com o link para o seu cliente abrir.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "integration_session": {
                      "$ref": "#/components/schemas/IntegrationSession"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/NotYoursOrNotFound"
          },
          "422": {
            "description": "Falha de validação. Um `customer_uuid` que não é seu também cai aqui.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormValidationError"
                },
                "example": {
                  "errors": {
                    "source_ids.0.customer_uuid": [
                      "The selected customer does not belong to this merchant."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/check-status": {
      "get": {
        "tags": [
          "Merchant"
        ],
        "operationId": "getStatus",
        "summary": "Estado do serviço",
        "description": "Verificação de saúde, sem autenticação e fora do limite de requisições. Responde **503** quando alguma dependência está fora. Use para monitoração, não como parte de um fluxo.",
        "security": [],
        "responses": {
          "200": {
            "description": "Tudo no ar.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degraded"
                      ]
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "checks": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "fail"
                        ]
                      }
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "timestamp": "2026-09-25T12:00:00+00:00",
                  "checks": {
                    "database": "ok",
                    "cache": "ok",
                    "queue": "ok"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Alguma dependência está fora.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "timestamp": {
                      "type": "string"
                    },
                    "checks": {
                      "type": "object"
                    }
                  }
                },
                "example": {
                  "status": "degraded",
                  "timestamp": "2026-09-25T12:00:00+00:00",
                  "checks": {
                    "database": "ok",
                    "cache": "fail",
                    "queue": "ok"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A chave de API do merchant. Vai em toda requisição, exceto no DELETE de conexão."
      },
      "customerToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-customer-token",
        "description": "O `api_token` devolvido na criação do cliente. Restringe a chamada àquele cliente."
      }
    },
    "parameters": {
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "required": false,
        "description": "A API não impõe máximo. Peça páginas razoáveis.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 15
        }
      },
      "SortBy": {
        "name": "sortBy",
        "in": "query",
        "required": false,
        "description": "Nome de coluna. O valor `rand` ordena aleatoriamente.",
        "schema": {
          "type": "string"
        }
      },
      "Descending": {
        "name": "descending",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "CustomerUuid": {
        "name": "uuid",
        "in": "path",
        "required": true,
        "description": "`uuid` do cliente.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "IntegrationUuid": {
        "name": "uuid",
        "in": "path",
        "required": true,
        "description": "`uuid` da conexão do cliente.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "AdsCustomerIntegration": {
        "name": "customer_integration",
        "in": "query",
        "required": true,
        "description": "O `uuid` da conexão. Identifica a conta de anúncios e a integração. Vai **sempre na query**, em todas as rotas de ads; no corpo é ignorado.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "AdsObjectId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "O `id` do objeto, o numérico que a plataforma de anúncios deu a ele (no Meta, o mesmo do Gerenciador de Anúncios), que vale para qualquer objeto da conta; ou o `uuid` do Connect, que vale para os que o Connect guarda.",
        "schema": {
          "type": "string",
          "example": "120250000000000001"
        }
      },
      "AdsIdempotencyKeyRequired": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Chave sua, única por operação (até 255 caracteres). **Sempre no header, nunca no corpo.** Gere uma vez, antes da primeira tentativa, e reenvie a mesma em toda repetição: uma chave nova a cada tentativa cria tudo de novo.\n\n- Mesma chave e mesmo pedido: devolve `200` com o corpo da primeira resposta e o header `Idempotent-Replay: true`, sem tocar na integração.\n- Mesma chave com outro pedido: `422 idempotency_key_reused`.\n- Mesma chave enquanto a primeira ainda roda: `409 operation_in_progress`, com `Retry-After`.\n- Mesma chave depois de uma falha: **retoma**. O que a primeira tentativa já criou é reaproveitado, não criado de novo.",
        "schema": {
          "type": "string",
          "maxLength": 255,
          "example": "order-8812-ad-1"
        }
      },
      "AdsIdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Opcional aqui. Com ela, repetir a chamada devolve a primeira resposta em vez de escrever de novo. Mesmas regras de `Idempotency-Key` das criações. **Sempre no header.**",
        "schema": {
          "type": "string",
          "maxLength": 255,
          "example": "order-8812-ad-1"
        }
      },
      "AdsSource": {
        "name": "source",
        "in": "query",
        "required": false,
        "description": "`connect` (padrão) lê do banco do Connect: o que o Connect criou ou já escreveu nesta conta, como o `GET /posts`. `external` lê a conta ao vivo na integração, incluindo o que foi criado fora do Connect.\n\nUma conta que já tinha campanhas antes do Connect **lista vazio** com `connect` até a primeira escrita pelo Connect. Isso é esperado: use `external` para ver o que existe na conta.",
        "schema": {
          "type": "string",
          "enum": [
            "connect",
            "external"
          ],
          "default": "connect"
        }
      },
      "AdsRefresh": {
        "name": "refresh",
        "in": "query",
        "required": false,
        "description": "Com `source=connect`, relê na integração os objetos desta resposta e atualiza `status`, `name` e `synced_at` (um objeto que sumiu ganha `deleted_at`). Com `source=external`, ignora o cache de 120 s.",
        "schema": {
          "type": "boolean"
        }
      },
      "AdsPerPage": {
        "name": "per_page",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 15
        }
      }
    },
    "schemas": {
      "MerchantSettings": {
        "type": "object",
        "required": [
          "uuid",
          "name",
          "app_url",
          "redirect_url",
          "logo_url",
          "trial_ends_at",
          "is_paying",
          "created_at",
          "updated_at",
          "total_customers",
          "available_integrations"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "app_url": {
            "type": "string"
          },
          "redirect_url": {
            "type": "string"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "trial_ends_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO-8601. Difere de `created_at`/`updated_at`, que vêm no formato `Y-m-d H:i:s`."
          },
          "is_paying": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "examples": [
              "2026-09-02 17:07:26"
            ]
          },
          "updated_at": {
            "type": "string",
            "examples": [
              "2026-09-02 17:07:26"
            ]
          },
          "rate_limit_per_minute": {
            "type": "string",
            "description": "Ausente quando a conta não tem configuração de limites. String, não número."
          },
          "rate_limit_per_second": {
            "type": "string"
          },
          "total_customers": {
            "type": "integer"
          },
          "available_integrations": {
            "type": "array",
            "description": "O que o plano do merchant libera.",
            "items": {
              "type": "object",
              "required": [
                "name",
                "slug"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Customer": {
        "type": "object",
        "required": [
          "uuid",
          "name",
          "created_at",
          "updated_at",
          "trial_ends_at",
          "is_paying",
          "merchant"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "examples": [
              "2026-09-02 17:07:34"
            ]
          },
          "updated_at": {
            "type": "string",
            "examples": [
              "2026-09-02 17:07:34"
            ]
          },
          "trial_ends_at": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "2026-09-16 17:07:34"
            ]
          },
          "is_paying": {
            "type": "boolean"
          },
          "merchant": {
            "type": "string",
            "description": "Nome do merchant, não um objeto."
          }
        }
      },
      "CustomerCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Customer"
          },
          {
            "type": "object",
            "required": [
              "api_token"
            ],
            "properties": {
              "api_token": {
                "type": "string",
                "description": "64 caracteres hexadecimais. O valor do header `x-customer-token` deste cliente. **Devolvido só aqui, e irrecuperável.**"
              }
            }
          }
        ]
      },
      "CustomerWithIntegrations": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Customer"
          },
          {
            "type": "object",
            "required": [
              "integrations"
            ],
            "properties": {
              "integrations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "uuid",
                    "integration",
                    "name",
                    "slug",
                    "status"
                  ],
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "É este uuid que os endpoints de métricas pedem."
                    },
                    "integration": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Nome da plataforma."
                    },
                    "name": {
                      "type": "string",
                      "description": "Nome da conta conectada."
                    },
                    "slug": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "$ref": "#/components/schemas/IntegrationStatus"
                    },
                    "icon": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "color": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "CustomerIntegration": {
        "type": "object",
        "required": [
          "uuid",
          "source_id",
          "source_name",
          "status",
          "created_at",
          "updated_at",
          "integration"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "source_id": {
            "type": "string",
            "description": "Identificador da conta na plataforma de origem."
          },
          "source_name": {
            "type": "string",
            "description": "Nome da conta conectada."
          },
          "status": {
            "$ref": "#/components/schemas/IntegrationStatus"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "currency": {
            "type": "string",
            "description": "Presente apenas nas plataformas de anúncios que informam moeda."
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "profile_picture_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Foto de perfil da conta, pronta para usar num <img>. Preenchida para Páginas do Facebook e para contas do Meta Ads, que usam a foto da Página que anunciam. É null nas demais plataformas e nos primeiros instantes depois de integrar, enquanto a foto é buscada."
          },
          "integration": {
            "type": "object",
            "required": [
              "name",
              "slug"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              }
            }
          }
        }
      },
      "IntegrationStatus": {
        "type": "string",
        "enum": [
          "active",
          "expired",
          "revoked",
          "synchronizing",
          "synchronization_error"
        ],
        "description": "Só `active` produz métricas. `expired` e `revoked` exigem que o cliente reautorize por uma nova sessão."
      },
      "IntegrationSessionRequest": {
        "type": "object",
        "properties": {
          "redirect_url": {
            "type": "string",
            "format": "uri",
            "description": "Para onde levar o cliente ao fim da autorização. Só `http` e `https`."
          },
          "locale": {
            "type": "string",
            "enum": [
              "pt_BR",
              "en",
              "es",
              "fr"
            ],
            "description": "Idioma da tela de autorização."
          },
          "expires_in_minutes": {
            "type": "integer",
            "minimum": 1,
            "default": 5
          },
          "close_on_finish": {
            "type": "boolean",
            "default": false,
            "description": "Fecha a aba ao terminar, em vez de redirecionar."
          },
          "enable_multi_account_selection": {
            "type": "boolean",
            "default": false
          },
          "limit_reached_url": {
            "type": "string",
            "format": "uri",
            "description": "Só `http` e `https`."
          },
          "limits": {
            "type": "array",
            "description": "Restrições aplicadas durante a autorização. Um nome não suportado não é recusado aqui: ele falha depois, dentro da tela.",
            "items": {
              "$ref": "#/components/schemas/ResourceLimit"
            }
          },
          "source_slug": {
            "type": "string",
            "description": "Abre a sessão direto numa plataforma. Só tem efeito junto com `source_ids`."
          },
          "source_ids": {
            "type": "array",
            "description": "Contas já conhecidas, para reaproveitar autorização entre clientes do mesmo merchant.",
            "items": {
              "type": "object",
              "required": [
                "customer_uuid",
                "source_id"
              ],
              "properties": {
                "customer_uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "source_id": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ResourceLimit": {
        "type": "object",
        "required": [
          "name",
          "value"
        ],
        "properties": {
          "name": {
            "type": "string",
            "enum": [
              "integration_count",
              "same_type_integration",
              "same_integration_across_customers",
              "available_integrations"
            ]
          },
          "value": {
            "description": "Um inteiro para os três primeiros; um array de slugs para `available_integrations`.",
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          }
        }
      },
      "IntegrationSession": {
        "type": "object",
        "required": [
          "session_uuid",
          "session_link",
          "expires_at",
          "merchant",
          "merchant_uuid",
          "customer",
          "customer_uuid",
          "close_on_finish",
          "enable_multi_account_selection"
        ],
        "properties": {
          "session_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "session_link": {
            "type": "string",
            "format": "uri",
            "description": "A URL para onde levar o cliente. É o único campo que a sua aplicação precisa usar."
          },
          "expires_at": {
            "type": "string",
            "description": "ISO-8601."
          },
          "merchant": {
            "type": "string"
          },
          "merchant_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "customer": {
            "type": "string"
          },
          "customer_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "redirect_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "close_on_finish": {
            "type": "boolean"
          },
          "locale": {
            "type": [
              "string",
              "null"
            ]
          },
          "limits": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/ResourceLimit"
            }
          },
          "limit_reached_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "enable_multi_account_selection": {
            "type": "boolean"
          },
          "source_slug": {
            "type": "string",
            "description": "Presente só quando enviado junto com `source_ids`."
          },
          "source_ids": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "MetricsRequest": {
        "type": "object",
        "required": [
          "start",
          "end",
          "metrics"
        ],
        "description": "Informe `customer_integration` ou `customer_integration_uuids`: um dos dois é obrigatório.",
        "properties": {
          "customer_integration": {
            "type": "string",
            "format": "uuid",
            "description": "Uma conexão. `uuid` vindo de `/customers/settings`."
          },
          "customer_integration_uuids": {
            "type": "array",
            "description": "Várias conexões na mesma chamada. Todas do cliente do token.",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "start": {
            "type": "string",
            "format": "date",
            "description": "Precisa ser menor ou igual a `end`."
          },
          "end": {
            "type": "string",
            "format": "date"
          },
          "comparison_start": {
            "type": "string",
            "format": "date",
            "description": "Período de comparação. Só é considerado se `comparison_end` também vier."
          },
          "comparison_end": {
            "type": "string",
            "format": "date"
          },
          "client_timezone": {
            "type": "string",
            "default": "America/Sao_Paulo",
            "description": "Identificador de timezone, como `America/Sao_Paulo`."
          },
          "metrics": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/MetricRequestItem"
            }
          }
        }
      },
      "MetricRequestItem": {
        "type": "object",
        "required": [
          "id",
          "reference_key",
          "component",
          "metrics"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "**Precisa ser um uuid.** É a chave sob a qual o resultado volta, então gere um por métrica pedida."
          },
          "reference_key": {
            "type": "string",
            "description": "Identificador da métrica na plataforma, como `ig:story_replies`. Descubra os disponíveis no Connect Explorer.",
            "examples": [
              "ig:story_replies",
              "ig:followers_gender"
            ]
          },
          "component": {
            "type": "string",
            "description": "Formato do resultado. Determina a forma do valor devolvido.",
            "examples": [
              "number_v1",
              "chart_v1",
              "datatable_v1"
            ]
          },
          "metrics": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "Os valores pedidos dentro daquela métrica."
          },
          "dimensions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Detalhamento do resultado."
          },
          "entity_id": {
            "type": "string"
          },
          "entity_type": {
            "type": "string"
          }
        }
      },
      "MetricFailure": {
        "type": "object",
        "description": "Substitui o resultado de uma métrica que falhou isoladamente. A requisição segue 200: as outras métricas do lote vêm normalmente.",
        "required": [
          "message",
          "type"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "invalid_metrics_combination",
              "no_data_in_period",
              "internal_error",
              "expired_token"
            ]
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "description": "Não há `links`. `sortBy` e `descending` são o eco dos parâmetros enviados.",
        "required": [
          "current_page",
          "last_page",
          "path",
          "per_page",
          "total"
        ],
        "properties": {
          "current_page": {
            "type": "integer"
          },
          "from": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_page": {
            "type": "integer"
          },
          "path": {
            "type": "string"
          },
          "per_page": {
            "type": [
              "integer",
              "string"
            ]
          },
          "to": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total": {
            "type": "integer"
          },
          "sortBy": {
            "type": [
              "string",
              "null"
            ]
          },
          "descending": {
            "type": [
              "boolean",
              "string"
            ]
          }
        }
      },
      "SuccessMessage": {
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          }
        }
      },
      "FailureMessage": {
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        }
      },
      "MessageError": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "error_code": {
            "type": "string",
            "description": "Identificador estável da recusa, quando ela tem um. É por ele que se ramifica, não pela mensagem.",
            "example": "ads_object_not_found"
          }
        }
      },
      "FormValidationError": {
        "type": "object",
        "description": "O envelope de validação mais comum: um mapa de campo para lista de mensagens.",
        "required": [
          "errors"
        ],
        "properties": {
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "supported_values": {
            "type": "object",
            "description": "Presente quando um campo recusado é um enum: traz, para cada campo que falhou, a lista do que era aceito. Um campo aninhado responde pelo prefixo: `targeting.genders` aparece como `targeting`.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "MetricsValidationError": {
        "type": "object",
        "description": "O outro envelope de 422, usado pelas recusas dos endpoints de métricas.",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "error_code": {
            "type": "string",
            "description": "Identificador estável da recusa.",
            "example": "validation_error"
          },
          "extra": {
            "description": "Contexto da recusa. Para token expirado, traz `integration_status`.",
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        }
      },
      "DiscoveryListMeta": {
        "type": "object",
        "required": [
          "cached",
          "cached_at"
        ],
        "properties": {
          "cached": {
            "type": "boolean",
            "description": "Se esta resposta veio do cache do Connect. A descoberta é o cache mais longo do módulo (600 s), e `refresh=true` fura."
          },
          "cached_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Quando a leitura foi buscada na integração. Um post recém-publicado só aparece depois disso."
          }
        }
      },
      "Page": {
        "type": "object",
        "description": "Uma página do Facebook que o token administra. O `id` é o `creative.page_id` de um anúncio.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "picture_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "can_post": {
            "type": "boolean",
            "description": "Se o token pode publicar por esta página."
          },
          "instagram_account_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "A conta do Instagram ligada a esta página, quando existe. É o `creative.instagram_account_id`."
          }
        }
      },
      "InstagramAccount": {
        "type": "object",
        "description": "Uma conta do Instagram que a conta de anúncios pode usar.",
        "properties": {
          "id": {
            "type": "string"
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Post": {
        "type": "object",
        "description": "Um conteúdo orgânico que um anúncio pode impulsionar. As duas fontes chegam na mesma forma, mas **só um post de `source: instagram` pode ir em `creative.source_post_id`**.",
        "properties": {
          "id": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "instagram",
              "facebook"
            ]
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "`image`, `video`, `carousel_album`, … conforme a integração classifica."
          },
          "caption": {
            "type": [
              "string",
              "null"
            ]
          },
          "permalink": {
            "type": [
              "string",
              "null"
            ]
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Pixel": {
        "type": "object",
        "description": "Um pixel da conta de anúncios. O `id` vai em `adset.facebook_ads.promoted_object.pixel_id` de um conjunto.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_fired_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_unavailable": {
            "type": "boolean"
          }
        }
      },
      "PixelEvent": {
        "type": "object",
        "description": "Um evento que o pixel registrou nos últimos 90 dias, com a contagem do período.",
        "properties": {
          "event_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "count": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "CustomConversion": {
        "type": "object",
        "description": "Uma conversão personalizada. O `id` vai em `adset.facebook_ads.promoted_object.custom_conversion_id`.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "event_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sempre minúsculo, como todo enum desta API."
          },
          "pixel_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_unavailable": {
            "type": "boolean"
          }
        }
      },
      "Audience": {
        "type": "object",
        "description": "Um público personalizado da conta. O `id` vai em `targeting.custom_audiences`.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "subtype": {
            "type": [
              "string",
              "null"
            ]
          },
          "approximate_size": {
            "type": "object",
            "properties": {
              "lower": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "upper": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          }
        }
      },
      "TargetingResult": {
        "type": "object",
        "description": "Um resultado de busca de segmentação, na mesma forma para os três tipos: a integração responde em três formatos diferentes e identifica lugar por `key` em vez de `id`.\n\n**Onde cada resultado é usado:** `interest` e `behavior` vão em `targeting.interests`. Geo é diferente: só **país** cabe em `targeting.countries`; cidade, região e bairro entram por `facebook_ads.targeting.raw.geo_locations` (`cities`, `regions`, …), e é o `subtype` que diz qual.",
        "properties": {
          "id": {
            "type": "string",
            "description": "O id que a segmentação espera. Para geo, é a `key` da integração."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "interest",
              "geo",
              "behavior"
            ],
            "description": "O tipo de busca que produziu o resultado."
          },
          "subtype": {
            "type": [
              "string",
              "null"
            ],
            "description": "Só em geo: `country`, `region`, `city`, `neighborhood`, `zip`. Sem ele o resultado não é utilizável, porque cada um vai num campo diferente."
          },
          "path": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "A hierarquia de categorias, do mais geral ao mais específico. Vazio em geo."
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "country_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Só em geo."
          },
          "audience_size": {
            "type": [
              "object",
              "null"
            ],
            "description": "A faixa que a integração estima. É faixa, não número, e geo não tem.",
            "properties": {
              "lower": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "upper": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          }
        }
      },
      "CustomConversionCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "pixel_id",
          "rule"
        ],
        "description": "Uma conversão personalizada é definida pela **regra** que decide quando ela dispara, e é a regra que você manda. Uma das duas formas por vez.\n\nA regra por URL é a verificada contra uma conta real. A regra por evento existe no contrato, mas a integração a recusa em alguns pixels. A recusa dela chega a você como `ads_integration_error`, em vez de ser adivinhada aqui.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "pixel_id": {
            "type": "string",
            "description": "Obrigatório: a integração recusa a criação sem o pixel por trás da regra."
          },
          "rule": {
            "type": "object",
            "description": "Exatamente uma das duas chaves.",
            "oneOf": [
              {
                "required": [
                  "url_contains"
                ],
                "not": {
                  "required": [
                    "event"
                  ]
                }
              },
              {
                "required": [
                  "event"
                ],
                "not": {
                  "required": [
                    "url_contains"
                  ]
                }
              }
            ],
            "properties": {
              "url_contains": {
                "type": "string",
                "maxLength": 255,
                "description": "Dispara quando o endereço visitado contém este trecho."
              },
              "event": {
                "type": "string",
                "maxLength": 255,
                "description": "Dispara quando o pixel reporta este evento."
              }
            }
          },
          "event_type": {
            "type": "string",
            "maxLength": 64,
            "enum": [
              "add_payment_info",
              "add_to_cart",
              "add_to_wishlist",
              "complete_registration",
              "contact",
              "content_view",
              "customize_product",
              "donate",
              "find_location",
              "initiated_checkout",
              "lead",
              "other",
              "purchase",
              "schedule",
              "search",
              "start_trial",
              "submit_application",
              "subscribe"
            ],
            "description": "A categoria da conversão, de `custom_event_types` em `GET /ads/options`. A integração aceita um conjunto fechado, então um valor fora dele é recusado com `422` e a lista, em vez de recusado pela integração sem explicação. Omitido, a integração recebe `OTHER`."
          }
        }
      },
      "WebhookSubscription": {
        "type": "object",
        "description": "Um endereço da sua conta que recebe eventos. `merchant_id` e a chave de deduplicação da URL nunca saem daqui.",
        "required": [
          "id",
          "url",
          "events",
          "is_active"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Integration": {
        "type": "object",
        "description": "Uma plataforma do catálogo do Connect.",
        "required": [
          "id",
          "name",
          "slug",
          "type",
          "color",
          "icon",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "O identificador usado em `available_integrations`, nas sessões e em `GET /metrics/{integration_slug}`."
          },
          "type": {
            "type": "integer",
            "description": "Código interno da plataforma. Sem uso para o merchant."
          },
          "color": {
            "type": "string",
            "description": "Cor da marca, em hexadecimal."
          },
          "icon": {
            "type": "object",
            "required": [
              "name",
              "color"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "color": {
                "type": "string"
              }
            }
          },
          "enabled": {
            "type": "boolean",
            "description": "`false` é uma plataforma que o Connect ainda não oferece a nenhum merchant."
          },
          "created_at": {
            "type": "string",
            "examples": [
              "2024-09-13 14:12:56"
            ]
          },
          "updated_at": {
            "type": "string",
            "examples": [
              "2024-09-13 14:12:56"
            ]
          }
        }
      },
      "MetricDefinition": {
        "type": "object",
        "description": "Uma métrica que a plataforma oferece. Os cinco primeiros campos são exatamente um MetricRequestItem: copie-os para `metrics[]` de `/metrics/get-data`. O resto descreve a métrica e pode ser ignorado.",
        "required": [
          "id",
          "reference_key",
          "component",
          "metrics",
          "dimensions",
          "references"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Gerado a cada resposta. Serve como `id` do item pedido, ou gere o seu."
          },
          "reference_key": {
            "type": "string",
            "examples": [
              "fb_ads:spend",
              "fb_ads:insights_by_campaign"
            ]
          },
          "component": {
            "type": "string",
            "description": "O formato padrão do resultado desta métrica.",
            "examples": [
              "number_v1",
              "chart_v1",
              "datatable_v1"
            ]
          },
          "metrics": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Os valores que a métrica devolve por padrão. Qualquer chave de `meta.setup.metrics` pode substituí-los."
          },
          "dimensions": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "object",
                  "required": [
                    "field"
                  ],
                  "properties": {
                    "field": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": true
                }
              ]
            },
            "description": "O detalhamento padrão. Tabelas trazem objetos `{\"field\": ...}`; envie-os como vieram. Qualquer chave de `meta.setup.dimensions` pode substituí-los."
          },
          "references": {
            "type": "object",
            "description": "Como a métrica se apresenta a uma pessoa, no idioma pedido.",
            "properties": {
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "additionalProperties": true
      },
      "MetricDefinitionsSetup": {
        "type": "object",
        "description": "Tudo que a plataforma aceita em `metrics` e `dimensions`, chaveado pelo valor a enviar. `label` é o nome legível, no idioma pedido.",
        "required": [
          "metrics",
          "dimensions"
        ],
        "properties": {
          "metrics": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          },
          "dimensions": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          }
        }
      },
      "AdsError": {
        "type": "object",
        "description": "O único envelope de erro do módulo de anúncios. Ramifique por `error_code`, nunca pela mensagem.",
        "required": [
          "message",
          "error_code"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "error_code": {
            "type": "string",
            "example": "validation_error",
            "description": "`validation_error`, `forbidden`, `idempotency_key_required`, `idempotency_key_invalid`, `idempotency_key_reused`, `operation_in_progress`, `budget_level_mismatch`, `boosted_creative_not_replaceable`, `ads_connection_expired`, `ads_unsupported_integration`, `ads_object_not_found`, `ads_video_not_ready`, `ads_integration_error`, ou o código de recusa que a integração devolveu, em minúsculas."
          },
          "errors": {
            "type": "object",
            "description": "Só em `validation_error`: campo → mensagens.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "supported_values": {
            "type": "object",
            "description": "Só em `validation_error`, quando um campo recusado é um enum: o que era aceito.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "integration_error": {
            "type": [
              "object",
              "null"
            ],
            "description": "O erro cru da integração, quando a recusa veio dela.",
            "properties": {
              "integration": {
                "type": "string",
                "example": "meta_ads"
              },
              "code": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "subcode": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "user_message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "integration_status": {
            "type": "string",
            "description": "Em `ads_connection_expired`: o novo status da conexão.",
            "example": "expired"
          },
          "created": {
            "type": "array",
            "description": "O que a operação criou e **não** conseguiu desfazer, para você remover. Tudo nasce pausado, então não gasta.",
            "items": {
              "type": "object",
              "properties": {
                "level": {
                  "type": "string",
                  "enum": [
                    "campaign",
                    "adset",
                    "ad"
                  ]
                },
                "id": {
                  "type": "string"
                }
              }
            }
          },
          "video_id": {
            "type": "string",
            "description": "Em `ads_video_not_ready`: o vídeo já enviado. Repita a chamada com a mesma `Idempotency-Key`: o vídeo é reaproveitado."
          },
          "budget_level": {
            "type": "string",
            "enum": [
              "campaign",
              "adset"
            ],
            "description": "Em `budget_level_mismatch`: onde o orçamento desta campanha vive."
          },
          "retry_after": {
            "type": "integer",
            "description": "Em `operation_in_progress`: segundos até poder repetir."
          }
        }
      },
      "AdsBudget": {
        "type": [
          "object",
          "null"
        ],
        "description": "Orçamento na **moeda da conta de anúncios**, nunca em centavos: `50` são cinquenta reais numa conta em BRL.",
        "properties": {
          "amount": {
            "type": "number"
          },
          "type": {
            "type": "string",
            "enum": [
              "daily",
              "lifetime"
            ]
          },
          "level": {
            "type": "string",
            "enum": [
              "campaign",
              "adset"
            ],
            "description": "Onde o orçamento vive. Só na leitura."
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "example": "BRL"
          }
        }
      },
      "AdsBudgetInput": {
        "type": [
          "object",
          "null"
        ],
        "description": "Orçamento na **moeda da conta de anúncios**, nunca em centavos. O nível é onde ele está: na campanha é CBO, no conjunto é ABO. Em `facebook_ads` pode ficar em qualquer um dos dois, nunca nos dois.",
        "required": [
          "amount"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "exclusiveMinimum": 0,
            "example": 50
          },
          "type": {
            "type": "string",
            "enum": [
              "daily",
              "lifetime"
            ],
            "default": "daily",
            "description": "`lifetime` exige `schedule.end` no conjunto."
          }
        }
      },
      "AdsCampaign": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "O id do objeto na plataforma de anúncios (no Meta, o mesmo do Gerenciador de Anúncios)."
          },
          "uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "O id do Connect. `null` quando o objeto não está no banco do Connect (só em `source=external`)."
          },
          "origin": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "created",
              "imported",
              null
            ],
            "description": "`created`: o Connect criou. `imported`: foi criado fora e entrou no banco na primeira escrita pelo Connect."
          },
          "synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A última vez que o Connect conferiu este objeto na integração. Leituras do banco mostram o último estado conhecido; `refresh=true` atualiza."
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Apagado pelo Connect, ou descoberto como apagado. Só aparece com `include_deleted=true`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "active",
              "paused",
              null
            ]
          },
          "effective_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudget"
          },
          "adsets_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "facebook_ads": {
            "type": "object",
            "properties": {
              "objective": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "spend_cap": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "bid_strategy": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdsAdset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "O id do objeto na plataforma de anúncios (no Meta, o mesmo do Gerenciador de Anúncios)."
          },
          "uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "O id do Connect. `null` quando o objeto não está no banco do Connect (só em `source=external`)."
          },
          "origin": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "created",
              "imported",
              null
            ],
            "description": "`created`: o Connect criou. `imported`: foi criado fora e entrou no banco na primeira escrita pelo Connect."
          },
          "synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A última vez que o Connect conferiu este objeto na integração. Leituras do banco mostram o último estado conhecido; `refresh=true` atualiza."
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Apagado pelo Connect, ou descoberto como apagado. Só aparece com `include_deleted=true`."
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "active",
              "paused",
              null
            ]
          },
          "effective_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudget"
          },
          "schedule": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "start": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "end": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "targeting": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "countries": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "age_min": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "age_max": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "genders": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "facebook_ads": {
            "type": "object",
            "properties": {
              "optimization_goal": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "billing_event": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bid_strategy": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bid_amount": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "placements": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true
              },
              "targeting": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "interests": {
                    "type": "array"
                  },
                  "custom_audiences": {
                    "type": "array"
                  },
                  "excluded_custom_audiences": {
                    "type": "array"
                  },
                  "advantage_audience": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "raw": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdsAd": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "O id do objeto na plataforma de anúncios (no Meta, o mesmo do Gerenciador de Anúncios)."
          },
          "uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "O id do Connect. `null` quando o objeto não está no banco do Connect (só em `source=external`)."
          },
          "origin": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "created",
              "imported",
              null
            ],
            "description": "`created`: o Connect criou. `imported`: foi criado fora e entrou no banco na primeira escrita pelo Connect."
          },
          "synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A última vez que o Connect conferiu este objeto na integração. Leituras do banco mostram o último estado conhecido; `refresh=true` atualiza."
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Apagado pelo Connect, ou descoberto como apagado. Só aparece com `include_deleted=true`."
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "adset_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "active",
              "paused",
              null
            ]
          },
          "effective_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "format": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "image",
              "video",
              "post",
              null
            ],
            "description": "`post` é um impulsionamento."
          },
          "headline": {
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "link_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "call_to_action": {
            "type": [
              "string",
              "null"
            ]
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "facebook_ads": {
            "type": "object",
            "properties": {
              "creative_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "page_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "instagram_account_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "post_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdsPageMeta": {
        "type": "object",
        "description": "A paginação padrão dos resources do Connect. Com `source=external`, a integração pagina por cursor e não informa o total: `total` e `last_page` não vêm, e `links.next` é `null` na última página.",
        "required": [
          "current_page",
          "path",
          "per_page"
        ],
        "properties": {
          "current_page": {
            "type": "integer"
          },
          "from": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_page": {
            "type": "integer"
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "active": {
                  "type": "boolean"
                }
              }
            }
          },
          "path": {
            "type": "string"
          },
          "per_page": {
            "type": "integer"
          },
          "to": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "AdsPageLinks": {
        "type": "object",
        "properties": {
          "first": {
            "type": [
              "string",
              "null"
            ]
          },
          "last": {
            "type": [
              "string",
              "null"
            ]
          },
          "prev": {
            "type": [
              "string",
              "null"
            ]
          },
          "next": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdsCampaignInput": {
        "type": "object",
        "required": [
          "name",
          "facebook_ads"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "default": "paused"
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudgetInput"
          },
          "facebook_ads": {
            "type": "object",
            "required": [
              "objective"
            ],
            "additionalProperties": false,
            "properties": {
              "objective": {
                "type": "string",
                "enum": [
                  "awareness",
                  "traffic",
                  "engagement",
                  "leads",
                  "app_promotion",
                  "sales"
                ],
                "description": "Obrigatório ao criar. Não muda depois."
              },
              "special_ad_categories": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Obrigatório para crédito, emprego, moradia e política."
              },
              "spend_cap": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Limite de gasto da campanha, na moeda da conta. `null` remove."
              }
            }
          }
        }
      },
      "AdsCampaignUpdate": {
        "type": "object",
        "description": "Só o que for enviado muda. Pelo menos um campo.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ]
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudgetInput"
          },
          "facebook_ads": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "spend_cap": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Limite de gasto da campanha, na moeda da conta. `null` remove."
              }
            }
          }
        }
      },
      "AdsAdsetInput": {
        "type": "object",
        "required": [
          "campaign_id",
          "name",
          "targeting",
          "facebook_ads"
        ],
        "properties": {
          "campaign_id": {
            "type": "string",
            "description": "A campanha, pelo `id` dela ou pelo `uuid` do Connect."
          },
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "default": "paused"
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudgetInput"
          },
          "schedule": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "start": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "end": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "targeting": {
            "type": "object",
            "additionalProperties": false,
            "description": "O que toda integração de anúncios entende. O resto da segmentação vai em `facebook_ads.targeting`.",
            "properties": {
              "countries": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 2
                },
                "example": [
                  "BR"
                ]
              },
              "age_min": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 13,
                "maximum": 65
              },
              "age_max": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 13,
                "maximum": 65
              },
              "genders": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "all",
                    "male",
                    "female"
                  ]
                }
              }
            }
          },
          "facebook_ads": {
            "type": "object",
            "required": [
              "optimization_goal",
              "billing_event"
            ],
            "additionalProperties": false,
            "properties": {
              "optimization_goal": {
                "type": "string",
                "description": "Obrigatório ao criar. Valores em `GET /ads/options`."
              },
              "billing_event": {
                "type": "string",
                "description": "Obrigatório ao criar."
              },
              "bid_strategy": {
                "type": "string",
                "enum": [
                  "lowest_cost",
                  "bid_cap",
                  "cost_cap"
                ]
              },
              "bid_amount": {
                "type": "number",
                "exclusiveMinimum": 0,
                "description": "Exige `bid_strategy`."
              },
              "placements": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "publisher_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "facebook_positions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "instagram_positions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "targeting": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "interests": {
                    "type": "array"
                  },
                  "custom_audiences": {
                    "type": "array"
                  },
                  "excluded_custom_audiences": {
                    "type": "array"
                  },
                  "advantage_audience": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "raw": {
                    "type": "object",
                    "description": "Spec de segmentação da Meta para o que o Connect não modela. Os campos modelados sempre vencem."
                  }
                }
              },
              "promoted_object": {
                "type": "object",
                "description": "Só ao criar. Pixel, página ou conversão personalizada precisam ser da conta da conexão."
              },
              "destination_type": {
                "type": "string",
                "description": "Só ao criar."
              },
              "attribution_spec": {
                "type": "array",
                "description": "Só ao criar."
              }
            }
          }
        }
      },
      "AdsAdsetUpdate": {
        "type": "object",
        "description": "Só o que for enviado muda. Uma segmentação parcial é mesclada com a atual.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ]
          },
          "budget": {
            "$ref": "#/components/schemas/AdsBudgetInput"
          },
          "schedule": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "start": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "end": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "targeting": {
            "type": "object",
            "additionalProperties": false,
            "description": "O que toda integração de anúncios entende. O resto da segmentação vai em `facebook_ads.targeting`.",
            "properties": {
              "countries": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 2
                },
                "example": [
                  "BR"
                ]
              },
              "age_min": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 13,
                "maximum": 65
              },
              "age_max": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 13,
                "maximum": 65
              },
              "genders": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "all",
                    "male",
                    "female"
                  ]
                }
              }
            }
          },
          "facebook_ads": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "optimization_goal": {
                "type": "string",
                "description": "Obrigatório ao criar. Valores em `GET /ads/options`."
              },
              "billing_event": {
                "type": "string",
                "description": "Obrigatório ao criar."
              },
              "bid_strategy": {
                "type": "string",
                "enum": [
                  "lowest_cost",
                  "bid_cap",
                  "cost_cap"
                ]
              },
              "bid_amount": {
                "type": "number",
                "exclusiveMinimum": 0,
                "description": "Exige `bid_strategy`."
              },
              "placements": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "publisher_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "facebook_positions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "instagram_positions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "targeting": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "interests": {
                    "type": "array"
                  },
                  "custom_audiences": {
                    "type": "array"
                  },
                  "excluded_custom_audiences": {
                    "type": "array"
                  },
                  "advantage_audience": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "raw": {
                    "type": "object",
                    "description": "Spec de segmentação da Meta para o que o Connect não modela. Os campos modelados sempre vencem."
                  }
                }
              }
            }
          }
        }
      },
      "AdsAdInput": {
        "type": "object",
        "required": [
          "format",
          "link_url",
          "media",
          "facebook_ads"
        ],
        "additionalProperties": false,
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "image",
              "video"
            ]
          },
          "headline": {
            "type": "string",
            "maxLength": 255
          },
          "body": {
            "type": "string",
            "maxLength": 2000
          },
          "description": {
            "type": "string",
            "maxLength": 255
          },
          "link_url": {
            "type": "string",
            "format": "uri"
          },
          "call_to_action": {
            "type": "string",
            "description": "Valores em `GET /ads/options`."
          },
          "media": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1,
            "items": {
              "type": "object",
              "required": [
                "type"
              ],
              "additionalProperties": false,
              "description": "Uma imagem por `url` ou `hash`; um vídeo por `url` ou `id`, sempre com `thumbnail_url`.",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "image",
                    "video"
                  ]
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "hash": {
                  "type": "string",
                  "description": "Imagem já enviada à conta."
                },
                "id": {
                  "type": "string",
                  "description": "Vídeo já enviado à conta."
                },
                "thumbnail_url": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "facebook_ads": {
            "type": "object",
            "required": [
              "page_id"
            ],
            "additionalProperties": false,
            "properties": {
              "page_id": {
                "type": "string",
                "description": "Precisa ser uma página da conta da conexão."
              },
              "instagram_account_id": {
                "type": "string"
              },
              "url_tags": {
                "type": "string"
              },
              "tracking_specs": {
                "type": "array"
              }
            }
          }
        }
      },
      "AdsBoostAdInput": {
        "type": "object",
        "required": [
          "post_id",
          "facebook_ads"
        ],
        "additionalProperties": false,
        "description": "O criativo vem do post. Textos e mídia não fazem parte de um impulsionamento.",
        "properties": {
          "post_id": {
            "type": "string",
            "description": "O post a impulsionar, de `GET /ads/facebook_ads/posts`."
          },
          "link_url": {
            "type": "string",
            "format": "uri"
          },
          "call_to_action": {
            "type": "string"
          },
          "facebook_ads": {
            "type": "object",
            "required": [
              "instagram_account_id"
            ],
            "additionalProperties": false,
            "properties": {
              "instagram_account_id": {
                "type": "string",
                "description": "A conta dona do post. É por ela que a posse do post é provada."
              },
              "page_id": {
                "type": "string"
              },
              "url_tags": {
                "type": "string"
              },
              "tracking_specs": {
                "type": "array"
              }
            }
          }
        }
      },
      "AdsTreeRequest": {
        "type": "object",
        "required": [
          "name",
          "adset",
          "ad"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "O nome do anúncio, e o dos níveis criados que não tiverem um."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "default": "paused",
            "description": "O estado final da árvore. Tudo nasce pausado e é ativado no último passo."
          },
          "campaign": {
            "description": "`{\"id\": …}` usa uma campanha existente; sem `id`, descreve a que será criada. Proibido quando `adset.id` é enviado.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "budget": {
                    "$ref": "#/components/schemas/AdsBudgetInput"
                  },
                  "facebook_ads": {
                    "type": "object",
                    "required": [
                      "objective"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "objective": {
                        "type": "string",
                        "enum": [
                          "awareness",
                          "traffic",
                          "engagement",
                          "leads",
                          "app_promotion",
                          "sales"
                        ],
                        "description": "Obrigatório ao criar. Não muda depois."
                      },
                      "special_ad_categories": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Obrigatório para crédito, emprego, moradia e política."
                      },
                      "spend_cap": {
                        "type": [
                          "number",
                          "null"
                        ],
                        "description": "Limite de gasto da campanha, na moeda da conta. `null` remove."
                      }
                    }
                  }
                }
              }
            ]
          },
          "adset": {
            "description": "`{\"id\": …}` usa um conjunto existente; sem `id`, descreve o que será criado.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "budget": {
                    "$ref": "#/components/schemas/AdsBudgetInput"
                  },
                  "schedule": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "start": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time"
                      },
                      "end": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time"
                      }
                    }
                  },
                  "targeting": {
                    "type": "object",
                    "additionalProperties": false,
                    "description": "O que toda integração de anúncios entende. O resto da segmentação vai em `facebook_ads.targeting`.",
                    "properties": {
                      "countries": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 2,
                          "maxLength": 2
                        },
                        "example": [
                          "BR"
                        ]
                      },
                      "age_min": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "minimum": 13,
                        "maximum": 65
                      },
                      "age_max": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "minimum": 13,
                        "maximum": 65
                      },
                      "genders": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "all",
                            "male",
                            "female"
                          ]
                        }
                      }
                    }
                  },
                  "facebook_ads": {
                    "type": "object",
                    "required": [
                      "optimization_goal",
                      "billing_event"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "optimization_goal": {
                        "type": "string",
                        "description": "Obrigatório ao criar. Valores em `GET /ads/options`."
                      },
                      "billing_event": {
                        "type": "string",
                        "description": "Obrigatório ao criar."
                      },
                      "bid_strategy": {
                        "type": "string",
                        "enum": [
                          "lowest_cost",
                          "bid_cap",
                          "cost_cap"
                        ]
                      },
                      "bid_amount": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "description": "Exige `bid_strategy`."
                      },
                      "placements": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "publisher_platforms": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "facebook_positions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "instagram_positions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "targeting": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "interests": {
                            "type": "array"
                          },
                          "custom_audiences": {
                            "type": "array"
                          },
                          "excluded_custom_audiences": {
                            "type": "array"
                          },
                          "advantage_audience": {
                            "type": [
                              "boolean",
                              "null"
                            ]
                          },
                          "raw": {
                            "type": "object",
                            "description": "Spec de segmentação da Meta para o que o Connect não modela. Os campos modelados sempre vencem."
                          }
                        }
                      },
                      "promoted_object": {
                        "type": "object",
                        "description": "Só ao criar. Pixel, página ou conversão personalizada precisam ser da conta da conexão."
                      },
                      "destination_type": {
                        "type": "string",
                        "description": "Só ao criar."
                      },
                      "attribution_spec": {
                        "type": "array",
                        "description": "Só ao criar."
                      }
                    }
                  }
                }
              }
            ]
          },
          "ad": {
            "$ref": "#/components/schemas/AdsAdInput"
          }
        }
      },
      "AdsBoostRequest": {
        "type": "object",
        "required": [
          "name",
          "adset",
          "ad"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "O nome do anúncio, e o dos níveis criados que não tiverem um."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "default": "paused",
            "description": "O estado final da árvore. Tudo nasce pausado e é ativado no último passo."
          },
          "campaign": {
            "description": "`{\"id\": …}` usa uma campanha existente; sem `id`, descreve a que será criada. Proibido quando `adset.id` é enviado.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "budget": {
                    "$ref": "#/components/schemas/AdsBudgetInput"
                  },
                  "facebook_ads": {
                    "type": "object",
                    "required": [
                      "objective"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "objective": {
                        "type": "string",
                        "enum": [
                          "awareness",
                          "traffic",
                          "engagement",
                          "leads",
                          "app_promotion",
                          "sales"
                        ],
                        "description": "Obrigatório ao criar. Não muda depois."
                      },
                      "special_ad_categories": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Obrigatório para crédito, emprego, moradia e política."
                      },
                      "spend_cap": {
                        "type": [
                          "number",
                          "null"
                        ],
                        "description": "Limite de gasto da campanha, na moeda da conta. `null` remove."
                      }
                    }
                  }
                }
              }
            ]
          },
          "adset": {
            "description": "`{\"id\": …}` usa um conjunto existente; sem `id`, descreve o que será criado.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "budget": {
                    "$ref": "#/components/schemas/AdsBudgetInput"
                  },
                  "schedule": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "start": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time"
                      },
                      "end": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time"
                      }
                    }
                  },
                  "targeting": {
                    "type": "object",
                    "additionalProperties": false,
                    "description": "O que toda integração de anúncios entende. O resto da segmentação vai em `facebook_ads.targeting`.",
                    "properties": {
                      "countries": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 2,
                          "maxLength": 2
                        },
                        "example": [
                          "BR"
                        ]
                      },
                      "age_min": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "minimum": 13,
                        "maximum": 65
                      },
                      "age_max": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "minimum": 13,
                        "maximum": 65
                      },
                      "genders": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "all",
                            "male",
                            "female"
                          ]
                        }
                      }
                    }
                  },
                  "facebook_ads": {
                    "type": "object",
                    "required": [
                      "optimization_goal",
                      "billing_event"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "optimization_goal": {
                        "type": "string",
                        "description": "Obrigatório ao criar. Valores em `GET /ads/options`."
                      },
                      "billing_event": {
                        "type": "string",
                        "description": "Obrigatório ao criar."
                      },
                      "bid_strategy": {
                        "type": "string",
                        "enum": [
                          "lowest_cost",
                          "bid_cap",
                          "cost_cap"
                        ]
                      },
                      "bid_amount": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "description": "Exige `bid_strategy`."
                      },
                      "placements": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "publisher_platforms": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "facebook_positions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "instagram_positions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "targeting": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "interests": {
                            "type": "array"
                          },
                          "custom_audiences": {
                            "type": "array"
                          },
                          "excluded_custom_audiences": {
                            "type": "array"
                          },
                          "advantage_audience": {
                            "type": [
                              "boolean",
                              "null"
                            ]
                          },
                          "raw": {
                            "type": "object",
                            "description": "Spec de segmentação da Meta para o que o Connect não modela. Os campos modelados sempre vencem."
                          }
                        }
                      },
                      "promoted_object": {
                        "type": "object",
                        "description": "Só ao criar. Pixel, página ou conversão personalizada precisam ser da conta da conexão."
                      },
                      "destination_type": {
                        "type": "string",
                        "description": "Só ao criar."
                      },
                      "attribution_spec": {
                        "type": "array",
                        "description": "Só ao criar."
                      }
                    }
                  }
                }
              }
            ]
          },
          "ad": {
            "$ref": "#/components/schemas/AdsBoostAdInput"
          }
        }
      },
      "AdsAdUpdate": {
        "type": "object",
        "description": "Só o que for enviado muda. Mudar um texto troca o criativo e manda o anúncio de volta para revisão. `headline` e `description` aceitam `null` para apagar.",
        "properties": {
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ]
          },
          "headline": {
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "link_url": {
            "type": "string",
            "format": "uri"
          },
          "call_to_action": {
            "type": "string"
          }
        }
      },
      "AdsDuplicateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Sem nome, a integração dá um. A cópia nasce sempre pausada."
          }
        }
      },
      "AdsValidation": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "results": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "level": {
                      "type": "string",
                      "enum": [
                        "campaign",
                        "adset",
                        "ad"
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "validated",
                        "skipped"
                      ],
                      "description": "`skipped`: o nível depende de um pai que ainda não existe na integração, e só é validado na criação de verdade."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "AdsDeleted": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "deleted": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "AdsOptions": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "additionalProperties": true,
            "properties": {
              "integration_slug": {
                "type": "string"
              },
              "budget": {
                "type": "object",
                "additionalProperties": true,
                "description": "Em quais níveis o orçamento pode ficar, e de que tipos."
              },
              "common": {
                "type": "object",
                "additionalProperties": true,
                "description": "Os valores dos campos que toda integração de anúncios tem."
              },
              "facebook_ads": {
                "type": "object",
                "additionalProperties": true,
                "description": "O bloco desta integração, nível a nível: os campos aceitos e os valores de cada um."
              }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthenticated": {
        "description": "Chave de API ausente, inválida ou mal formada no header",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "example": {
              "message": "Unauthenticated."
            }
          }
        }
      },
      "MerchantAccessDenied": {
        "description": "A chave é válida, mas o acesso da conta está suspenso por cobrança",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "example": {
              "message": "Merchant trial ended"
            }
          }
        }
      },
      "NotYoursOrNotFound": {
        "description": "O recurso não existe ou não pertence à sua conta. A API não distingue os dois casos, e por isso não devolve 404.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "example": {
              "message": "This action is unauthorized."
            }
          }
        }
      },
      "CustomerTokenError": {
        "description": "Problema com o `x-customer-token`",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "examples": {
              "ausente": {
                "value": {
                  "message": "Missing Customer Token"
                }
              },
              "invalido": {
                "value": {
                  "message": "Invalid Customer Token"
                }
              },
              "de_outro_merchant": {
                "value": {
                  "message": "Merchant doesnt have access to this resource"
                }
              }
            }
          }
        }
      },
      "CustomerAccessError": {
        "description": "Problema com o `x-customer-token`, ou cliente sem acesso",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "examples": {
              "ausente": {
                "value": {
                  "message": "Missing Customer Token"
                }
              },
              "invalido": {
                "value": {
                  "message": "Invalid Customer Token"
                }
              },
              "teste_encerrado": {
                "summary": "O cliente passou dos 14 dias e não está marcado como pagante",
                "value": {
                  "message": "Customer trial ended, mark them as paying to continue using resource"
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Limite de requisições da conta excedido. Tente novamente com backoff.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageError"
            },
            "example": {
              "message": "Too many requests. Please slow down."
            }
          }
        }
      },
      "AdsForbidden": {
        "description": "A conexão informada não é deste cliente.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "This action is unauthorized.",
              "error_code": "forbidden"
            }
          }
        }
      },
      "AdsValidationError": {
        "description": "O pedido foi recusado antes de chegar à integração: um campo inválido (`validation_error`, com `errors` e `supported_values`), a `Idempotency-Key` ausente ou reaproveitada, a conexão expirada (`ads_connection_expired`) ou fora das integrações de anúncios (`ads_unsupported_integration`). Uma recusa de negócio da própria integração também pode chegar como 422, com `integration_error`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "The given data was invalid.",
              "error_code": "validation_error",
              "errors": {
                "campaign.facebook_ads.objective": [
                  "The selected campaign.facebook_ads.objective is invalid."
                ]
              },
              "supported_values": {
                "campaign.facebook_ads.objective": [
                  "awareness",
                  "traffic",
                  "engagement",
                  "leads",
                  "app_promotion",
                  "sales"
                ]
              }
            }
          }
        }
      },
      "AdsObjectNotFound": {
        "description": "O objeto não existe na conta de anúncios desta conexão, ou o `uuid` não é de um objeto que o Connect guarda. Um id de outra conta que o token alcance é recusado aqui, e a resposta não confirma que ele existe em outro lugar.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "Not Found",
              "error_code": "ads_object_not_found"
            }
          }
        }
      },
      "AdsConflict": {
        "description": "`operation_in_progress`: a mesma `Idempotency-Key` ainda está rodando (`Retry-After` diz quando repetir). `budget_level_mismatch`: o orçamento desta campanha vive no outro nível. `ads_video_not_ready`: a integração ainda processa o vídeo; repita com a mesma chave.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "The budget of this campaign lives on the adset; send it there instead.",
              "error_code": "budget_level_mismatch",
              "budget_level": "adset"
            }
          }
        }
      },
      "AdsIntegrationRefused": {
        "description": "A integração recusou a operação. O status é o que ela devolveu, e `integration_error` traz o código dela.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "Você não pode usar o orçamento do conjunto com o orçamento da campanha.",
              "error_code": "ads_integration_error",
              "integration_error": {
                "integration": "meta_ads",
                "code": 100,
                "subcode": 4834002,
                "user_message": "Você não pode usar o orçamento do conjunto com o orçamento da campanha."
              }
            }
          }
        }
      },
      "AdsIntegrationUnavailable": {
        "description": "A integração não respondeu, ou respondeu com erro dela. Sem status para espelhar, é **502**. Repetir com a mesma `Idempotency-Key` retoma de onde parou.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AdsError"
            },
            "example": {
              "message": "The ads integration could not be reached",
              "error_code": "ads_integration_error",
              "integration_error": {
                "integration": "meta_ads",
                "code": null,
                "subcode": null,
                "user_message": null
              }
            }
          }
        }
      }
    }
  }
}
