Look up CNPJ in Lovable
This guide shows how to add CNPJ lookup (the Brazilian company tax ID) to an app built with Lovable: the user types a CNPJ and the app shows the legal name, registration status and main activity, coming from the CNPJAPI API. You do not need to code: the guide has a ready-to-paste prompt for Lovable and reference code to check what the AI generated.
The most important point is where your API key lives. It goes in a backend secret of the project, never in the page code. The guide explains why and how.
Before you start: create the account and generate the API key
To use the API you need an API key (a token that identifies your account). It is free to start.
- Go to https://app.cnpjapi.com.br and create your account on the free plan (no card required).
- Confirm your e-mail and sign in to the portal.
- Inside the portal, generate your API key. It starts with
cnpj_(for example,cnpj_a1b2c3...). Copy it and keep it somewhere safe - the key is shown once. - This key goes in the
Authorizationheader, asBearer cnpj_your_key, on every request.
Details in Authentication. Treat the key like a password: whoever holds it consumes your quota.
How it works in Lovable
Lovable has no official CNPJAPI connector. The integration is a server function of the app that receives the CNPJ from the screen, calls the API with your key and returns the result. Depending on the project type, Lovable creates it as a Supabase Edge Function (Lovable Cloud) or as an API route of the app itself. Either way, the prompt below works for both.
Why not call the API straight from the page? Because everything in the page goes to the visitor's browser. A key in the page code can be copied by anyone who opens the browser inspector, and whoever holds the key spends your quota. In the server function the key is stored as a secret and never leaves the server.
The function must also accept signed-in users only. Otherwise, anyone who finds the function address can call it and spend your quota just the same.
Step by step
- In your Lovable project, turn on the backend (Lovable Cloud or the Supabase integration) and user sign-in, if they are not on yet.
- Paste the prompt below into the Lovable chat.
- When Lovable asks for the CNPJAPI key, paste your
cnpj_...into the secrets field it shows. Do not paste the key in the chat: what you write in the chat stays in the project history. - Test with a known CNPJ, for example
00.776.574/0001-56, signed in to the app.
Ready-to-paste prompt
I want a CNPJ lookup screen using the CNPJAPI API (https://api.cnpjapi.com.br).
Security rules (mandatory):
- The API key is secret. Store it as a backend secret named CNPJAPI_KEY
and ask me for the value through the secrets field. Never put the key in the frontend code.
- Create a server function named consultar-cnpj: a Supabase Edge Function or, if this
project does not allow Edge Functions, an API route of the app itself. Only it calls
CNPJAPI.
- The function serves signed-in users only: take the token from the request
Authorization header, validate it with supabase.auth.getUser(token) and return 401 if
there is no user. The project's public (anon) key does not count as a signed-in user.
- In the function CORS, allow the POST and OPTIONS methods and the headers supabase-js
sends (authorization, x-client-info, apikey, content-type and the x-supabase-client-*).
- Any unexpected failure (network, invalid response) returns 502, never an error without CORS.
How the function calls the API:
- Receives { cnpj } in the JSON body. Removes dots, slash, hyphen and spaces and converts
to uppercase. Accepts 14 characters: 12 letters or digits followed by 2 digits.
If it does not match, returns 400 with { error: "Invalid CNPJ." }.
- Makes GET https://api.cnpjapi.com.br/{cnpj} with the header
Authorization: Bearer <value of CNPJAPI_KEY>.
- If the API returns 200, returns the JSON as is.
- 404: returns 404 with { error: "CNPJ not found." }.
- 422: returns 400 with { error: "Invalid CNPJ." }.
- 429: returns 429 with a message in the error field. The CNPJAPI body has a codigo
field: if it is "cota_diaria", use "Daily lookup limit reached. Try again tomorrow.";
if it is "cota_mensal", use "Monthly lookup quota reached."; otherwise, if the
Retry-After header is up to 120 seconds, use "Too many lookups in a row. Try again in
N seconds."; if not, "Lookup limit reached. Try again later.".
- Any other error: returns 502 with { error: "Could not look up the CNPJ right now." }.
Screen:
- A CNPJ field and a Look up button, visible to signed-in users only.
- Call the function sending the session token in the Authorization header (with
supabase.functions.invoke for an Edge Function, or fetch for an app route).
- Show RazaoSocial, NomeFantasia, SituacaoCadastral.Descricao and AtividadePrincipal.Descricao.
- On error, read the function's JSON response and show the error field.
Function reference code
To check what Lovable generated, below is the function as a Supabase Edge Function. If your project got an app API route instead, the code looks different, but the steps are the same: take the token from the header, check the user, call the API with the key from the secret and translate the errors.
// supabase/functions/consultar-cnpj/index.ts
import { createClient } from "jsr:@supabase/supabase-js@2";
const cors = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers":
"authorization, x-client-info, apikey, content-type, x-supabase-client-platform, " +
"x-supabase-client-platform-version, x-supabase-client-runtime, x-supabase-client-runtime-version",
};
const reply = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), {
status,
headers: { ...cors, "Content-Type": "application/json" },
});
const quotaMessages: Record<string, string> = {
cota_diaria: "Daily lookup limit reached. Try again tomorrow.",
cota_mensal: "Monthly lookup quota reached.",
};
Deno.serve(async (req) => {
if (req.method === "OPTIONS") return new Response("ok", { headers: cors });
try {
// 1. Signed-in users only (the project's public key is not enough).
const token = (req.headers.get("Authorization") ?? "").replace(/^Bearer /, "");
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_ANON_KEY")!,
);
const { data } = await supabase.auth.getUser(token);
if (!data?.user) return reply({ error: "Sign in to look up." }, 401);
// 2. 14-character CNPJ (accepts punctuation and the alphanumeric CNPJ).
const input = (await req.json().catch(() => null)) ?? {};
const clean = String(input.cnpj ?? "").replace(/[.\/\-\s]/g, "").toUpperCase();
if (!/^[0-9A-Z]{12}[0-9]{2}$/.test(clean)) {
return reply({ error: "Invalid CNPJ." }, 400);
}
// 3. Call CNPJAPI with the key stored in the CNPJAPI_KEY secret.
const resp = await fetch(`https://api.cnpjapi.com.br/${clean}`, {
headers: { Authorization: `Bearer ${Deno.env.get("CNPJAPI_KEY")}` },
});
if (resp.ok) return reply(await resp.json());
if (resp.status === 404) return reply({ error: "CNPJ not found." }, 404);
if (resp.status === 422) return reply({ error: "Invalid CNPJ." }, 400);
if (resp.status === 429) {
const limit = await resp.json().catch(() => ({}));
const seconds = parseInt(resp.headers.get("Retry-After") ?? "", 10);
const error = quotaMessages[limit.codigo] ??
(seconds > 0 && seconds <= 120
? `Too many lookups in a row. Try again in ${seconds} seconds.`
: "Lookup limit reached. Try again later.");
return reply({ error }, 429);
}
// 401/403 here = wrong or revoked CNPJAPI key (a configuration problem).
return reply({ error: "Could not look up the CNPJ right now." }, 502);
} catch {
return reply({ error: "Could not look up the CNPJ right now." }, 502);
}
});
And, on the screen, the call to the Edge Function with error handling (for an app route, the
same with fetch, sending Authorization: Bearer with the session token):
const { data, error } = await supabase.functions.invoke("consultar-cnpj", {
body: { cnpj },
});
if (error) {
const body = await error.context?.json?.().catch(() => null);
showError(body?.error ?? "Could not look up the CNPJ right now.");
} else {
showCompany({
legalName: data.RazaoSocial,
tradeName: data.NomeFantasia,
status: data.SituacaoCadastral?.Descricao,
activity: data.AtividadePrincipal?.Descricao,
});
}
The main response fields:
RazaoSocial- legal name;NomeFantasia- trade name (may be empty);SituacaoCadastral.Descricao- "Ativa" (active), "Baixada" (closed), etc.;AtividadePrincipal.Descricao- main CNAE activity in words.
The full list is in CNPJ lookup.
"Not found" and rate limits
The API returns 404 when the CNPJ does not exist in the public registry and 429 when you go over the per-minute limit, the daily cap or the monthly quota. The function above turns each case into a ready-made message for the screen.
On the CNPJAPI free plan, the API accepts a limited number of lookups per minute, per day and per month. An app open to many users reaches that limit fast. For larger volumes, upgrade to a plan with a higher limit and a comfortable monthly quota. See the limits per plan.
Security checklist
- The
cnpj_...key does not appear in any frontend file (search the project code forcnpj_). - The key is stored as the backend secret
CNPJAPI_KEY, not in the Lovable chat. - The function returns 401 when called without sign-in: sign out and call the function (or route) address directly, without the token.
- If your app's sign-up is open to anyone, remember that every registered user consumes your quota. If the app is internal, turn off open sign-up; if it is public, require e-mail confirmation.
- A signed-in user can still click nonstop. If the app is public, ask Lovable for a per-user limit (for example, at most 30 lookups per hour per account, counted in a database table).
- If the key leaks, revoke it in the portal and generate another; then update the secret.
Notes
- There is no official CNPJAPI connector in Lovable - it is a server function of the app that calls the API.
- The same approach works for any app with a Supabase backend, built with Lovable or not.
Next steps
- Response fields and full contract
- Look up CNPJ with Node.js
- Look up CNPJ with no code (spreadsheets and automation)
- Limits and plans and Errors
Create your free account at https://app.cnpjapi.com.br and add CNPJ lookup to your app today.