apipj API
API de consulta de CNPJ a partir dos dados abertos da Receita Federal. Formato `completo` (padrão, documento estruturado) ou `simplificado` (formato plano com campos já formatados). Suporte a CNPJ alfanumérico.
API de consulta de CNPJ a partir dos dados abertos da Receita Federal. Formato `completo` (padrão, documento estruturado) ou `simplificado` (formato plano com campos já formatados). Suporte a CNPJ alfanumérico.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/apipj:apipj-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
{"openapi":"3.1.0","info":{"title":"apipj","version":"0.1.0","description":"API de consulta de CNPJ a partir dos dados abertos da Receita Federal. Formato `completo` (padrão, documento estruturado) ou `simplificado` (formato plano com campos já formatados). Suporte a CNPJ alfanumérico.","contact":{"email":"brunogalizzi@masterbi.com"}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Authorization: Bearer <chave>"},"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"},"cookie":{"type":"apiKey","in":"cookie","name":"__Host-apipj_session"}},"schemas":{}},"paths":{"/v1/status":{"get":{"summary":"Status do serviço e do dataset","tags":["Público"],"description":"Sem autenticação. Informa o mês do dataset da Receita Federal carregado e a quantidade de CNPJs.","responses":{"200":{"description":"Default Response"}}}},"/v1/valida/{cnpj}":{"get":{"summary":"Valida formato e dígitos verificadores de um CNPJ","tags":["Público"],"description":"Sem autenticação e sem consumo de cota. Aceita CNPJ numérico ou alfanumérico (IN RFB 2.229/2024), com ou sem pontuação. Não consulta a base.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":32},"in":"path","name":"cnpj","required":true,"description":"CNPJ com ou sem pontuação (numérico ou alfanumérico)"}],"responses":{"200":{"description":"Default Response"}}}},"/v1/cnpj/{cnpj}":{"get":{"summary":"Consulta os dados cadastrais de um CNPJ","tags":["Consulta"],"description":"Autenticação obrigatória: `Authorization: Bearer <chave>` (preferido), `X-API-Key: <chave>` ou `?token=<chave>` (obsoleto); no site, o cookie de sessão (mesma origem) também vale. Valem o limite por minuto e a cota mensal do plano do usuário (chaves e sessão somam na mesma cota). Sem autenticação: 401 `unauthorized`. Cabeçalhos sempre presentes: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Limit, X-Quota-Remaining, X-Quota-Reset. Erros: 400 `invalid_cnpj`, 401 `unauthorized`, 404 `not_found`, 429 `rate_limited` ou `quota_exceeded` (com `Retry-After` / `upgrade_url`).","parameters":[{"schema":{"type":"string","enum":["completo","simplificado"],"default":"completo"},"in":"query","name":"formato","required":false,"description":"Formato da resposta: `completo` (padrão: documento estruturado, com códigos e descrições) ou `simplificado` (formato plano para integrações que preferem campos já formatados: datas DD/MM/AAAA, CNPJ, CEP e telefone com máscara)"},{"schema":{"type":"string","maxLength":80,"deprecated":true},"in":"query","name":"token","required":false,"description":"Chave de API na query string (obsoleto: use o header Authorization)","deprecated":true},{"schema":{"type":"string","minLength":1,"maxLength":32},"in":"path","name":"cnpj","required":true,"description":"CNPJ com ou sem pontuação (numérico ou alfanumérico)"}],"security":[{"bearer":[]},{"apiKey":[]},{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/busca":{"get":{"summary":"Busca CNPJs ativos por atividade (CNAE principal) e município","tags":["Consulta"],"description":"Lista estabelecimentos **ativos** pela atividade econômica principal (`cnae`) e/ou pelo município (`municipio`); pelo menos um dos dois filtros é obrigatório (senão 400 `validation_error`). Autenticação como em `/v1/cnpj`: `Authorization: Bearer <chave>` (preferido), `X-API-Key` ou o cookie de sessão do site; sem autenticação, 401 `unauthorized`. Paginação por cursor: a página tem no máximo o limite por minuto do plano (ou `limite`, de 1 até esse valor; teto de 1000) e é cortada pelo que ainda resta no minuto e na cota do mês. Envie `proximo_cursor` como `cursor` para a página seguinte; `null` indica o fim. **Cada CNPJ devolvido consome 1 do limite por minuto e 1 da cota mensal**, na mesma contabilidade de `/v1/cnpj` (mesma chave, mesma cota). Página vazia não consome nada. Os resultados não trazem o quadro de sócios (`socios` no formato completo, `qsa` no simplificado): sócios só na consulta individual. CNPJs cujo titular se opôs à busca ficam de fora (e do `total`). Resposta: `{dataset_month, total, resultados, proximo_cursor}`, com os cabeçalhos X-RateLimit-* e X-Quota-*. Erros: 400 `validation_error` ou `cursor_invalido` (cursor de outra busca, de outro mês da base ou malformado), 401 `unauthorized`, 429 `rate_limited` (com `Retry-After`) ou `quota_exceeded` (com `upgrade_url`), 503 `busca_indisponivel` (índice em atualização) ou `busca_em_breve` (antes do início da vigência).","parameters":[{"schema":{"type":"string","maxLength":20},"in":"query","name":"cnae","required":false,"description":"CNAE da atividade principal, 7 dígitos, com ou sem pontuação (4781400 ou 47.81-4-00)"},{"schema":{"type":"string","maxLength":20},"in":"query","name":"municipio","required":false,"description":"Município: código da Receita Federal (4 dígitos, o `endereco.municipio.codigo_rfb`) ou do IBGE (7 dígitos)"},{"schema":{"type":"string","maxLength":512},"in":"query","name":"cursor","required":false,"description":"Valor de `proximo_cursor` da página anterior (mesmos filtros)"},{"schema":{"type":"string","enum":["completo","simplificado"],"default":"completo"},"in":"query","name":"formato","required":false,"description":"Formato de cada resultado, como em `/v1/cnpj` (sem os sócios)"},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limite","required":false,"description":"Tamanho máximo da página, de 1 até o limite por minuto do plano (padrão: esse limite)"},{"schema":{"type":"string","maxLength":80,"deprecated":true},"in":"query","name":"token","required":false,"description":"Chave de API na query string (obsoleto: use o header Authorization)","deprecated":true}],"security":[{"bearer":[]},{"apiKey":[]},{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/plans":{"get":{"summary":"Planos e limites públicos","tags":["Público"],"description":"Mesmo conteúdo de config/plans.json, só os planos públicos, mais `billing {provider, test_mode, available, requires_document}` (provedor de pagamento e se as assinaturas estão abertas).","responses":{"200":{"description":"Default Response"}}}},"/v1/auth/signup":{"post":{"summary":"Cria conta, sessão e a chave inicial","tags":["Conta"],"description":"Devolve a chave de API uma única vez. Exige `accept_tos: true` (grava versão e data do aceite); `tos_version` é opcional e, se enviada, precisa ser a versão atual dos termos (senão 400 `tos_required`). Limite: 20 cadastros por IP por dia. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password","name","accept_tos"],"additionalProperties":false,"properties":{"email":{"type":"string","minLength":5,"maxLength":254},"password":{"type":"string","minLength":1,"maxLength":256},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Nome, em uma linha: quebra de linha ou caractere de controle → 400 `validation_error` (`field: \"name\"`); espaços repetidos viram um só"},"cpf_cnpj":{"type":"string","maxLength":24,"description":"CPF ou CNPJ (opcional no gratuito, obrigatório para assinar)"},"accept_tos":{"type":"boolean"},"tos_version":{"type":"string","maxLength":20,"description":"Versão dos termos exibida ao usuário (opcional). Se divergir da versão atual, a resposta é 400 `tos_required` com a versão vigente."}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/login":{"post":{"summary":"Login com e-mail e senha (cookie de sessão)","tags":["Conta"],"description":"Resposta genérica em falha (também para conta criada com o Google, que não tem senha). Bloqueio de 15 minutos após 5 falhas (e-mail + IP) ou 20 falhas (IP). Conta encerrada há menos de 30 dias é reativada pelo login (`reactivated: true`). Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"additionalProperties":false,"properties":{"email":{"type":"string","minLength":1,"maxLength":254},"password":{"type":"string","minLength":1,"maxLength":256}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/logout":{"post":{"summary":"Encerra a sessão atual","tags":["Conta"],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/accept-tos":{"post":{"summary":"Registra o aceite da versão atual dos termos","tags":["Conta"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accept_tos"],"additionalProperties":false,"properties":{"accept_tos":{"type":"boolean"}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/password":{"post":{"summary":"Troca a senha (encerra as outras sessões)","tags":["Conta"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["current_password","new_password"],"additionalProperties":false,"properties":{"current_password":{"type":"string","minLength":1,"maxLength":256},"new_password":{"type":"string","minLength":1,"maxLength":256}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/keys":{"get":{"summary":"Lista as chaves ativas (só o prefixo)","tags":["Chaves"],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Cria uma chave (mostrada uma única vez)","tags":["Chaves"],"description":"Máximo de 5 chaves ativas por conta e 10 criações por hora. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":60}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/keys/{id}":{"delete":{"summary":"Revoga uma chave imediatamente","tags":["Chaves"],"parameters":[{"schema":{"type":"integer","minimum":1},"in":"path","name":"id","required":true}],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/me":{"get":{"summary":"Usuário, plano, validade e uso do mês","tags":["Conta"],"description":"Devolve `user`, o plano efetivo (`plan` = id, `plan_name`), `plan_valid_until`, `cancel_requested`, `plan_started_at` e `refund_eligible_until` (plano pago: confirmação do primeiro pagamento e fim dos 7 dias de arrependimento, ou `null`), `limits`, `usage` do mês, `tos_required`, `auth {password, google, google_email}` (formas de entrar: senha própria, Google vinculado e o e-mail Google mascarado), `avisos` (avisos do painel ativos na data e ainda sem ciência da conta: `[{id, titulo, texto, links: [{rotulo, url}]}]`; a primeira devolução registra a exibição), `checkout {pending, plan, plan_name}` (pedido de assinatura aguardando pagamento, lido só do banco local, sem consultar o provedor: com `pending: true` o painel mostra a faixa de pagamento pendente e busca os detalhes em `GET /v1/billing/pending`) e `billing {provider, test_mode, available, requires_document, portal}` (provedor de pagamento: `stripe` ou `asaas`; modo de teste; se a conta pode assinar agora; se o checkout pede CPF/CNPJ; se há portal do cliente para trocar cartão e ver faturas).","security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/avisos/{id}/ciencia":{"post":{"summary":"Registra a ciência de um aviso do painel","tags":["Conta"],"description":"Grava a data e hora em que a conta deu ciência do aviso (idempotente: vale o primeiro registro). 404 `not_found` para aviso inexistente ou fora da janela de exibição. Requer o header `X-Requested-With: apipj`.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"id","required":true}],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/usage":{"get":{"summary":"Uso do mês, limites do plano e data de reset","tags":["Conta"],"description":"Aceita sessão (cookie) ou chave de API. `used`/`quota`/`remaining` e `reset_at` (ISO) também aparecem na raiz, além do bloco `usage`.","security":[{"cookie":[]},{"bearer":[]},{"apiKey":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/checkout":{"post":{"summary":"Inicia a assinatura de um plano pago","tags":["Billing"],"description":"Provedor em `GET /v1/plans` → `billing.provider`. **Stripe:** cria (ou reaproveita, com `reused: true`) uma Checkout Session de assinatura mensal e devolve `{url, plan, value, reused, return_supported: true}`; `url` é a página do Stripe (checkout.stripe.com), que pede o cartão e o CPF/CNPJ (nada disso passa por esta API) e volta para `/painel?pagamento=retorno&session_id=…` (ou `/painel?pagamento=cancelado`). Sem `cpf_cnpj`. Em produção com o Stripe em modo de teste, só contas liberadas assinam: as demais recebem 403 `checkout_indisponivel` (\"Assinaturas abrindo em breve\"); preço do Stripe divergente de `config/plans.json`: 503 `checkout_indisponivel`. **Asaas:** cria (ou reaproveita) a assinatura no Asaas e devolve `{url, plan, value, reused, return_supported}`: `url` é a fatura hospedada, onde o cliente informa o cartão (nenhum dado de cartão passa por esta API). A assinatura é criada com retorno automático para `/painel?pagamento=retorno` (`return_supported: true`: abra a fatura na mesma aba); se o Asaas recusar o retorno (site não cadastrado na conta Asaas), ela é refeita sem ele e `return_supported` vem `false` (abra a fatura em outra aba e mantenha o painel consultando `POST /v1/billing/sync`). Com `reused: true` a fatura pendente do mesmo plano foi reaproveitada. Exige CPF/CNPJ: se o cadastro não tem, envie `cpf_cnpj` no corpo (fica gravado na conta). Pedido anterior já pago no Asaas e ainda não ativado: 409 `checkout_already_paid` (o plano é ativado na hora e nada é recriado). Conta em revisão por contestação de pagamento: 403 `account_under_review`. Pedidos simultâneos da mesma conta são atendidos um de cada vez (o segundo do mesmo plano reaproveita a fatura do primeiro). Limite: 10 por minuto por IP e, por usuário, 6 por minuto e 30 por hora (429 `rate_limited` com `Retry-After`). Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"additionalProperties":false,"properties":{"plan":{"type":"string","minLength":1,"maxLength":30},"cpf_cnpj":{"type":"string","maxLength":24,"description":"CPF ou CNPJ do titular (só é usado se a conta ainda não tem um)"}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/pending":{"get":{"summary":"Pagamento pendente do pedido em andamento","tags":["Billing"],"description":"`{pending: null}` ou `{pending: {plan, plan_name, value, invoice_url, due_date, created_at, return_supported}}`: a fatura ainda não paga da assinatura criada pelo checkout (consulta o Asaas; guardada por 30 s por usuário). `invoice_url` reaproveita a mesma fatura (\"Continuar pagamento\"). Falha do Asaas: 502 `billing_unavailable`. `GET /v1/me` traz `checkout.pending` (só o banco local) para decidir se vale consultar esta rota.","security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/cancel-pending":{"post":{"summary":"Cancela o pedido ainda não pago","tags":["Billing"],"description":"Remove no Asaas a assinatura criada pelo checkout que ainda não foi paga e limpa o pedido: `{cancelled: true, plan, plan_name, plan_valid_until}` (o plano atual da conta, que não muda). 409 `no_pending_checkout` se não há pedido pendente; 409 `checkout_already_paid` se o Asaas já confirmou o pagamento (o plano é ativado na hora; para não renovar, use `POST /v1/billing/cancel`). Falha do Asaas: 502 `billing_unavailable`, nada muda. Numa troca de plano a assinatura anterior já foi removida no checkout: o plano atual segue até `plan_valid_until`, sem renovação. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/sync":{"post":{"summary":"Confere o pagamento do pedido no Asaas e ativa o plano","tags":["Billing"],"description":"Para a volta do Asaas (`/painel?pagamento=retorno`) e para o painel com pedido em andamento: reconsulta no Asaas as cobranças da assinatura da conta e, se o Asaas diz `CONFIRMED`/`RECEIVED`, ativa o plano pelo mesmo caminho do webhook (idempotente com ele: uma só ativação). Nunca ativa sem a confirmação do Asaas. Devolve `{status, plan, plan_name, plan_valid_until, limits: {rpm, monthly_quota}, activated, checked}`: `status` = `active` (plano pago vigente e nenhum pedido pendente), `pending` (pedido aguardando o pagamento; `plan` é o plano pedido) ou `none` (nenhum pedido e plano gratuito); `activated` = esta chamada ativou o plano; `checked` = o Asaas foi consultado nesta chamada (`false`: sem pedido pendente, consulta recente, teto de consultas ou Asaas indisponível; a resposta sai do estado local, sem erro). Limite: 30 por minuto por usuário (429 `rate_limited` com `Retry-After`). Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"session_id":{"type":"string","minLength":1,"maxLength":255,"description":"Stripe: o session_id do retorno do Checkout (/painel?pagamento=retorno&session_id=…); precisa ser da conta (senão 403 checkout_session_mismatch)"}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/cancel":{"post":{"summary":"Cancela a assinatura (plano vale até o fim do período pago) ou exerce o arrependimento","tags":["Billing"],"description":"No provedor que ativou o plano: no Stripe, `cancel_at_period_end` (a assinatura não renova e acaba no fim do período pago); no Asaas, remove a assinatura. O plano continua ativo até `plan_valid_until`; depois cai para o gratuito. Com `{\"refund\": true}` dentro de `refund_eligible_until` (7 dias da confirmação do primeiro pagamento do plano, CDC art. 49; termos §6.7): estorno da primeira cobrança no mesmo cartão e volta imediata ao gratuito. O estorno é integral quando o uso desde a ativação ficou em até 20% da cota mensal; acima disso é limitado à parte não utilizada (`refund_full: false`, cálculo em `usage` e no e-mail); uso igual ou acima da cota, ou fora das condições, responde 400 `refund_not_eligible` com `reason`. Um pedido de estorno por contratação: pedidos repetidos ou simultâneos recebem 400 `refund_not_eligible` (`ja_estornado`); erro do Asaas responde 502 e o pedido pode ser repetido; sem resposta do Asaas (timeout), 502 com o pedido mantido e orientação para falar com o suporte. Confirmação por e-mail nos dois casos. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"refund":{"type":"boolean","description":"true = desistência em 7 dias: estorno integral se o uso desde a ativação ficou em até 20% da cota mensal; acima disso, limitado à parte não utilizada (refund_full:false, cálculo em usage); uso igual ou acima da cota: 400 refund_not_eligible (uso_excessivo)"}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/billing/portal":{"post":{"summary":"Portal do cliente do Stripe (cartão e faturas)","tags":["Billing"],"description":"Plano pago ativado pelo Stripe: devolve `{url}` de uma sessão do portal do cliente do Stripe (billing.stripe.com, válida por pouco tempo; abra na hora), com volta para `/painel`. O portal serve só para trocar o cartão e ver as faturas; cancelar e desistir continuam em `POST /v1/billing/cancel`. Sem assinatura no Stripe: 400 `no_subscription`. Falha do Stripe: 502 `billing_unavailable`. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/account/close":{"post":{"summary":"Encerra a conta (carência de 30 dias para reativar)","tags":["Conta"],"description":"Confirma a senha (`password`) ou, em conta sem senha própria (criada com o Google), o e-mail da conta digitado de novo (`confirm_email`); cancela a assinatura no Asaas (se houver), revoga todas as chaves, encerra as sessões e marca a conta para eliminação após 30 dias (termos §4.7; política §8). Dentro da carência, um novo login reativa a conta. 400 `validation_error` se faltar o campo exigido pela conta (ver `auth.password` em /v1/me); 401 `unauthorized` se não confere (5 erros em 15 minutos bloqueiam por 15 minutos). Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"password":{"type":"string","minLength":1,"maxLength":256,"description":"Senha da conta (contas com senha própria)"},"confirm_email":{"type":"string","minLength":1,"maxLength":254,"description":"E-mail da conta, digitado de novo (contas sem senha, criadas com o Google)"}}}}}},"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/providers":{"get":{"summary":"Formas de login disponíveis","tags":["Conta"],"description":"`google: true` quando o login com Google está configurado; o site só mostra o botão nesse caso.","responses":{"200":{"description":"Default Response"}}}},"/v1/auth/google/start":{"get":{"summary":"Inicia o login com Google (navegação de topo, responde 302)","tags":["Conta"],"description":"Abrir como link (não por fetch). `intent`: `login` (padrão), `signup` (exige `tos` igual à versão vigente dos termos, marcada no formulário) ou `link` (vincula à conta da sessão atual). `next` só aceita `/painel`, `/precos`, `/sandbox`, `/consulta-cnpj-em-lote`, `/painel?assinar={id}` para um plano pago público de `config/plans.json` ou `/autorizar?pedido={id}` (página de consentimento do OAuth do MCP; id de 43 caracteres base64url) (comparação exata, codificado na URL; qualquer outro valor vira `/painel`). Grava um estado de uso único (10 min) e o cookie do fluxo, e redireciona ao Google com `state`, `nonce` e PKCE S256. Com o recurso desligado, ou `intent=link` sem sessão ou iniciado por outro site (`Sec-Fetch-Site`), redireciona para `/entrar?erro=google_falhou` ou `google_estado`; `intent=signup` vindo de outro site não vale como aceite (segue para a confirmação).","parameters":[{"schema":{"type":"string","enum":["login","signup","link"],"default":"login"},"in":"query","name":"intent","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"next","required":false},{"schema":{"type":"string","maxLength":20},"in":"query","name":"tos","required":false,"description":"Versão dos termos aceita no formulário (obrigatória em intent=signup)"}],"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/google/callback":{"get":{"summary":"Retorno do Google (responde 302)","tags":["Conta"],"description":"Confere o cookie do fluxo contra `state` (uso único, 10 min), troca o `code` (client_secret + code_verifier) e valida o id_token (RS256/JWKS, iss, aud, exp, nonce, email_verified). Destinos: conta já vinculada → `next` com sessão; `intent=link` → `/painel?google=vinculado`; conta com o mesmo e-mail → vínculo automático só se a posse do e-mail da conta já foi comprovada (conta sem senha própria) e o Google administra o endereço (@gmail.com/@googlemail.com ou `hd` igual ao domínio), senão `/entrar?google=vincular`; conta que já tem outra conta Google não troca o vínculo (`google_ja_vinculado`); sem conta → `intent=signup` com aceite cria a conta sem chave e vai a `/painel?boas-vindas=1` (com `next=/sandbox`, volta a `/sandbox`; com `next=/painel?assinar={id}`, vai a `/painel?assinar={id}&boas-vindas=1`), senão `/criar-conta?google=1` (confirmação). Erros: `/entrar?erro=google_cancelado|google_estado|google_falhou|google_email_nao_verificado|google_ja_vinculado`.","responses":{"200":{"description":"Default Response"}}}},"/v1/auth/google/pending":{"get":{"summary":"Dados da conta Google aguardando confirmação do cadastro","tags":["Conta"],"description":"Lê o cookie do cadastro pendente (10 min). `{email, name, tos_version}`; 401 `unauthorized` se não houver ou tiver expirado.","responses":{"200":{"description":"Default Response"}}}},"/v1/auth/google/complete":{"post":{"summary":"Confirma o cadastro com Google (aceite dos termos)","tags":["Conta"],"description":"Exige o cookie do cadastro pendente, `accept_tos: true` e `tos_version` igual à vigente (senão 400 `tos_required`). Cria a conta sem senha e sem chave, abre a sessão e apaga o pendente: 201 `{user, next}`. 401 se o pendente expirou; 409 `email_in_use`/`google_in_use` se a conta passou a existir. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accept_tos","tos_version"],"additionalProperties":false,"properties":{"accept_tos":{"type":"boolean"},"tos_version":{"type":"string","maxLength":20}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/v1/auth/google/unlink":{"post":{"summary":"Desvincula o Google da conta","tags":["Conta"],"description":"Só para contas com senha própria; sem senha, 400 `password_required` (seria impossível entrar de novo). Sem Google vinculado, responde ok. Requer o header `X-Requested-With: apipj`.","security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/webhooks/asaas":{"post":{"summary":"Webhook do Asaas (uso interno)","tags":["Interno"],"description":"Recebe eventos de cobrança/assinatura. Exige o header `asaas-access-token` igual ao token cadastrado no Asaas. Responde 200 assim que o evento é gravado; o processamento é assíncrono e idempotente pelo `id` do evento.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","event"],"properties":{"id":{"type":"string","minLength":1,"maxLength":200},"event":{"type":"string","minLength":1,"maxLength":80},"dateCreated":{"type":"string"},"payment":{"type":"object"},"subscription":{"type":"object"}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/webhooks/stripe":{"post":{"summary":"Webhook do Stripe (uso interno)","tags":["Interno"],"description":"Recebe eventos de checkout, fatura, assinatura, estorno e disputa. Exige o cabeçalho `Stripe-Signature` válido (HMAC-SHA256 com o segredo do endpoint, tolerância de 300 s). Responde 200 assim que o evento é gravado; o processamento é assíncrono e idempotente pelo `id` do evento.","responses":{"200":{"description":"Default Response"}}}},"/v1/oauth/pedido/{id}":{"get":{"summary":"Pedido de conexão de um aplicativo (página /autorizar)","tags":["Conta"],"description":"Dados do pedido criado por `GET /oauth/authorize` (10 minutos): `cliente {nome, host, tipo}` (host do client_id quando o cliente se identifica por URL), `redirect {host, loopback}` (para onde a pessoa volta), `loopback_apenas`, `acesso` (o que a autorização permite), `expira_em`, `conta {email, nome}` da sessão atual ou `null` e `tos_version`. 404 `pedido_expirado` se não existe, expirou ou já foi decidido.","parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/oauth/pedido/{id}/decisao":{"post":{"summary":"Autoriza ou recusa o aplicativo do pedido","tags":["Conta"],"description":"`{autorizar: true|false}` com sessão. Uso único: o pedido some depois da decisão. Devolve `{redirect}`, a URL de volta ao aplicativo com `code` e `state` (ou `error=access_denied`) e `iss`; a página navega até ela. 401 sem sessão; 404 `pedido_expirado`. Requer o header `X-Requested-With: apipj`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autorizar"],"additionalProperties":false,"properties":{"autorizar":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"in":"path","name":"id","required":true}],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/oauth/aplicativos":{"get":{"summary":"Aplicativos conectados à conta (OAuth)","tags":["Conta"],"description":"Concessões ativas: `{aplicativos: [{id, nome, host, redirect_host, tipo, criado_em, usado_em}]}`. Cada conexão autorizada (por exemplo, o conector do Claude) aparece uma vez.","security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/oauth/aplicativos/{id}":{"delete":{"summary":"Desconecta um aplicativo (revoga os tokens na hora)","tags":["Conta"],"description":"Revoga a concessão: o token de acesso e o refresh token do aplicativo param de valer imediatamente (o MCP responde 401 e o aplicativo pede para conectar de novo). 404 se não existe ou já foi revogada. Requer o header `X-Requested-With: apipj`.","parameters":[{"schema":{"type":"integer","minimum":1},"in":"path","name":"id","required":true}],"security":[{"cookie":[]}],"responses":{"200":{"description":"Default Response"}}}}},"servers":[{"url":"https://apipj.com.br"}],"tags":[{"name":"Público","description":"Sem autenticação"},{"name":"Consulta","description":"Consulta de CNPJ (exige chave de API ou sessão do site)"},{"name":"Conta","description":"Cadastro, login e perfil (sessão por cookie)"},{"name":"Chaves","description":"Chaves de API"},{"name":"Billing","description":"Assinaturas (Stripe; Asaas como alternativa)"},{"name":"Interno","description":"Rotas internas (webhooks)"}]}