Crie Regras inteligentes com a API, o MCP e automações
O campo rules dos links e QR Codes da CodeQR — endpoints, exemplos completos de requisição e resposta, todos os erros de validação, as tools do MCP que aceitam regras e o que Make, Zapier, Pluga e webhooks conseguem fazer.

Ao final desta página você consegue criar, alterar, ler e remover Regras inteligentes em links e QR Codes a partir do seu próprio código, de um agente de IA via servidor MCP e do Make, Zapier ou Pluga — com os payloads exatos e os erros exatos que a API devolve.
Disponibilidade
- Plano: Business ou superior (preços). Nos demais planos, toda requisição que contenha um array
rulesnão vazio é recusada com403 forbidden. - URL base da API:
https://api.codeqr.io. Autenticação:Authorization: Bearer <chave de API>— crie uma chave em Configurações → Chaves de API. Referência: docs.codeqr.io/api-reference. - Servidor MCP:
https://mcp.codeqr.io/mcp(Streamable HTTP, OAuth 2.0). Documentação: docs.codeqr.io/mcp.
Antes de começar
- Uma chave de API com permissão de escrita no workspace, e o domínio (
go.example.com) ou umlinkIdexistente. - Leia a Referência das Regras inteligentes para os valores aceitos por atributo — a API grava qualquer string de até 190 caracteres, então um valor que a requisição nunca carrega (
mobile,Brasil,BR-SP) é salvo e nunca combina.
O campo rules
rules é um array ordenado (máximo de 20 itens) nos objetos de link e de QR Code. A avaliação é de cima para baixo, a primeira que combina vence; sem combinação → a url do link.
attribute— Tipo: enum · Significado:device,country,city,region,continent,language,referrer,utm_source,utm_medium,utm_campaign,utm_term,utm_contentoperator— Tipo: enum · Significado:equals,not_equalsvalue— Tipo: string 1–190 · Significado: comparada por inteiro e sem diferenciar maiúsculas com o que a requisição carregaurl— Tipo: string (URL) · Significado: destino do tráfego que combina — ousplit— Tipo: array de 2–4{ "url", "weight" }· Significado: pesos inteiros de 1 a 100 que precisam somar 100
Restrições que o servidor aplica: attribute, operator e value vêm juntos ou não vêm; uma regra tem url ou split, nunca os dois; uma regra sem condição (todo o tráfego) precisa de split e precisa ser o último item.
Rótulo na UI → valor na API:
- Dispositivo / País / Cidade / Região (estado) / Continente / Idioma / Referenciador — Na API:
device/country/city/region/continent/language/referrer - Origem UTM / Mídia UTM / Campanha UTM / Termo UTM / Conteúdo UTM — Na API:
utm_source/utm_medium/utm_campaign/utm_term/utm_content - é / não é — Na API:
equals/not_equals - URL de destino (de uma regra)** — Na API:
url - Dividir tráfego (teste A/B) com URL da variante e Peso da variante (%) — Na API:
split[]comurleweight - Todo o tráfego — Na API: uma regra sem
attribute,operator,value - Valor de dispositivo macOS** — Na API:
"Mac OS"(tambémiOS,Android,Windows,Linux) - Botão Regras inteligentes desligado — Na API:
"rules": null
Endpoints que aceitam rules
POST /links— Uso: criar um link com regrasPUT /links/{linkId}— Uso: substituir as regras de um link (PATCHnão é suportado —405)POST /links/bulk— Uso: criar vários links; cada item aceitarulesPOST /qrcodes— Uso: criar um QR Code dinâmico do tipourlcom regrasPUT /qrcodes/{qrcodeId}— Uso: substituir as regras de um QR CodePOST /qrcodes/bulk— Uso: criar vários QR Codes; cada item aceitarules
Leia as regras de volta com GET /links/{linkId} ou GET /links/info?domain=go.example.com&key=baixe-o-app; o objeto do link inclui rules.
Criar um link com regras
curl -X POST https://api.codeqr.io/links \
-H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/app",
"domain": "go.example.com",
"key": "baixe-o-app",
"rules": [
{ "attribute": "device", "operator": "equals", "value": "iOS",
"url": "https://apps.apple.com/br/app/example-app/id1234567890" },
{ "attribute": "device", "operator": "equals", "value": "Android",
"url": "https://play.google.com/store/apps/details?id=com.example.app" }
]
}'200 OK:
{
"id": "cmswk759f0001j41i0vj1vmfq",
"domain": "go.example.com",
"key": "baixe-o-app",
"url": "https://example.com/app",
"archived": false,
"expiresAt": null,
"expiredUrl": null,
"password": null,
"externalId": null,
"trackConversion": false,
"proxy": false,
"title": null,
"description": null,
"image": null,
"video": null,
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"utm_term": null,
"utm_content": null,
"rewrite": false,
"doIndex": false,
"banned": false,
"flexible": false,
"filled": false,
"ios": null,
"android": null,
"geo": null,
"rules": [
{
"url": "https://apps.apple.com/br/app/example-app/id1234567890",
"value": "iOS",
"operator": "equals",
"attribute": "device"
},
{
"url": "https://play.google.com/store/apps/details?id=com.example.app",
"value": "Android",
"operator": "equals",
"attribute": "device"
}
],
"userId": "cm73yc6m70002mtesulffnrgb",
"folderId": null,
"projectId": "cm73y7wm100008j24i1b137wr",
"preRedirection": false,
"pageId": null,
"pageUrl": null,
"isFormMandatory": false,
"publicStats": false,
"clicks": 0,
"lastClicked": null,
"leads": 0,
"sales": 0,
"saleAmount": 0,
"createdAt": "2026-08-17T01:32:38.884Z",
"updatedAt": "2026-08-17T01:32:38.884Z",
"tagId": null,
"comments": null,
"notificationToken": null,
"useAsTemplate": false,
"tags": [],
"shortLink": "https://go.example.com/baixe-o-app",
"qrCode": "https://api.codeqr.io/qr?url=https://go.example.com/baixe-o-app?qr=1"
}Substituir as regras de um link e acrescentar uma divisão A/B
PUT substitui o array inteiro — envie todas as regras que quer manter.
curl -X PUT https://api.codeqr.io/links/cmswk759f0001j41i0vj1vmfq \
-H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{ "attribute": "device", "operator": "equals", "value": "iOS",
"url": "https://apps.apple.com/br/app/example-app/id1234567890" },
{ "attribute": "device", "operator": "equals", "value": "Android",
"url": "https://play.google.com/store/apps/details?id=com.example.app" },
{ "split": [
{ "url": "https://example.com/landing-a", "weight": 50 },
{ "url": "https://example.com/landing-b", "weight": 50 }
] }
]
}'200 OK devolve o mesmo objeto do link com as três regras; updatedAt muda e a resposta também traz "webhookIds": [].
Remover todas as regras
curl -X PUT https://api.codeqr.io/links/cmswk759f0001j41i0vj1vmfq \
-H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "rules": null }'200 OK com "rules": null; todo o tráfego vai para url. Enviar "rules": [] também interrompe o roteamento, mas grava um array vazio ("rules": []) e não aciona a verificação de plano.
QR Codes
QR Codes dinâmicos do tipo url aceitam as mesmas rules:
curl -X POST https://api.codeqr.io/qrcodes \
-H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "url",
"url": "https://example.com/menu",
"domain": "go.example.com",
"key": "cardapio",
"static": false,
"rules": [
{ "attribute": "language", "operator": "equals", "value": "pt", "url": "https://example.com/cardapio" },
{ "attribute": "language", "operator": "equals", "value": "es", "url": "https://example.com/menu-es" }
]
}'200 OK devolve o objeto do QR Code com "static": false e o array rules. Com "static": true a requisição falha: 403 forbidden — Smart rules can only be used on dynamic QR codes.
Criar vários links de uma vez
POST /links/bulk recebe um array de corpos de link; cada item aceita as suas próprias rules.
curl -X POST https://api.codeqr.io/links/bulk \
-H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '[
{ "url": "https://example.com/app", "domain": "go.example.com", "key": "baixe-o-app",
"rules": [ { "attribute": "device", "operator": "equals", "value": "iOS",
"url": "https://apps.apple.com/br/app/example-app/id1234567890" } ] },
{ "url": "https://example.com/menu", "domain": "go.example.com", "key": "cardapio",
"rules": [ { "attribute": "language", "operator": "equals", "value": "pt",
"url": "https://example.com/cardapio" } ] }
]'200 OK devolve um array com um objeto de link por item, cada um com as suas rules (mesmo formato da resposta de link único acima). POST /qrcodes/bulk funciona do mesmo jeito para QR Codes dinâmicos do tipo URL.
Ler os resultados por destino
Filtre o endpoint de análise por linkId e agrupe por top_urls:
curl -s "https://api.codeqr.io/analytics?event=composite&groupBy=top_urls&linkId=cmswk759f0001j41i0vj1vmfq&interval=24h" \ -H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx"
200 OK:
[
{ "url": "https://example.com/app", "clicks": 3, "leads": 0, "sales": 0, "amount": 0, "saleAmount": 0 },
{ "url": "https://apps.apple.com/br/app/example-app/id1234567890", "clicks": 3, "leads": 0, "sales": 0, "amount": 0, "saleAmount": 0 }
]Use event=clicks para só cliques. Identifique o link por linkId (ou externalId); com domain e key é preciso enviar também type=link, senão o endpoint devolve um array vazio.
Erros
- 401 —
error.code:unauthorized·error.message:Unauthorized: Login required.· Causa: chave de API ausente ou inválida - 403 —
error.code:forbidden·error.message:Smart rules are available on the Business plan and above. Upgrade to Business to use this feature.· Causa:rulesnão vazio vindo de um workspace Free, Starter ou Pro - 403 —
error.code:forbidden·error.message:Smart rules can only be used on dynamic QR codes.· Causa:static: truecom regras - 400 —
error.code:unprocessable_entity·error.message:custom: rules[0]: Split weights must add up to 100· Causa: soma dos pesos ≠ 100 - 400 —
error.code:unprocessable_entity·error.message:custom: rules: A rule without a condition matches all traffic, so it must be the last one· Causa: regra só de divisão fora da última posição - 400 —
error.code:unprocessable_entity·error.message:custom: rules[0]: A rule condition needs attribute, operator and value together· Causa: condição incompleta - 400 —
error.code:unprocessable_entity·error.message:custom: rules[0]: A rule needs either a destination url or a traffic split, never both· Causa:urlesplitna mesma regra - 400 —
error.code:unprocessable_entity·error.message:custom: rules[0]: A rule without a condition must split traffic· Causa: regra de todo o tráfego comurl - 400 —
error.code:unprocessable_entity·error.message:invalid_enum_value: rules[0].attribute: Invalid enum value. Expected 'device' | 'country' | … , received 'browser'· Causa: atributo desconhecido; mesmo padrão paraoperator - 400 —
error.code:unprocessable_entity·error.message:custom: rules[0].url: Invalid URL· Causa: destino não é uma URL - 400 —
error.code:unprocessable_entity·error.message:too_big: rules[0].value: String must contain at most 190 character(s)· Causa: valor longo demais - 400 —
error.code:unprocessable_entity·error.message:too_big: rules: Array must contain at most 20 element(s)· Causa: mais de 20 regras - 405 —
error.code: — ·error.message: — · Causa:PATCH /links/{id}; usePUT - 422 —
error.code:unprocessable_entity·error.message:Malicious URL detected· Causa: uma URL de regra ou de variante reprovou na verificação de segurança do destino
O corpo do erro tem a forma { "error": { "code", "message", "doc_url" }, "errors": [ … ] }. Repare no status 400 com unprocessable_entity no corpo para erros de schema.
SDKs
O SDK TypeScript @codeqr/ts (import Codeqr from '@codeqr/ts') envia rules em client.links.create(...), client.links.update(linkId, ...), client.qrcodes.create(...), client.qrcodes.update(qrcodeId, ...) e nos métodos em lote. Na versão 0.24.1 o tipo Rule ainda lista só os sete atributos originais (device, country, utm_source, utm_medium, utm_campaign, referrer, language), marca os quatro campos como obrigatórios e não tem split; a API aceita o formato completo, então passe uma divisão ou uma regra de city/region/continent/utm_term/utm_content com uma asserção de tipo até os tipos do SDK alcançarem a API:
import Codeqr from '@codeqr/ts';
const client = new Codeqr({ apiKey: process.env['CODEQR_API_KEY'] });
const link = await client.links.create({
url: 'https://example.com/app',
domain: 'go.example.com',
key: 'baixe-o-app',
rules: [
{ attribute: 'device', operator: 'equals', value: 'iOS',
url: 'https://apps.apple.com/br/app/example-app/id1234567890' },
{ attribute: 'device', operator: 'equals', value: 'Android',
url: 'https://play.google.com/store/apps/details?id=com.example.app' },
],
});
console.log(link.rules);Não existe SDK Python; chame os endpoints REST diretamente a partir do Python.
MCP
Tools que aceitam rules (array | null, máximo 20, mesmo formato de item da API): create_link, update_link. get_link_info (por linkId, externalId ou domain + key) devolve o objeto do link incluindo rules. create_qrcode e update_qrcode não aceitam rules — crie QR Codes com regras pela API ou pelo app.
As descrições das tools já declaram as restrições que um agente precisa: ordem de avaliação, url ou split (nunca os dois), a regra de todo o tráfego, os formatos de valor aceitos por atributo ("device: the operating system — "iOS", "Android", "Windows", "Mac OS" or "Linux". Never "mobile" or "desktop": those match nothing"), a janela fixa ("A visitor keeps the same variant across visits, for one hour, or 30 days when trackConversion is on.") e que null remove todas as regras — "on update_link, that is how a running test is ended."
Exemplo de pedido e a chamada resultante:
Crie um link em go.example.com para https://example.com/ que mande o Brasil para https://example.com/pt-br/ e divida os demais 50/50 entre https://example.com/a e https://example.com/b.
{
"url": "https://example.com/",
"domain": "go.example.com",
"rules": [
{ "attribute": "country", "operator": "equals", "value": "BR", "url": "https://example.com/pt-br/" },
{ "split": [
{ "url": "https://example.com/a", "weight": 50 },
{ "url": "https://example.com/b", "weight": 50 }
] }
]
}Toda tool devolve o objeto de resposta da API em JSON, então create_link, update_link e get_link_info entregam ao agente o objeto completo do link, incluindo rules. O servidor também valida rules localmente antes de chamar a API e responde Error: … em uma frase para os problemas de formato listados acima. Em planos abaixo do Business a API recusa a chamada inteira e o agente reporta a mensagem do 403.
Automações e webhooks: Make, Zapier, Pluga
- Make: os módulos Create a Link e Create a QR Code da CodeQR não têm campo de regras. Use Make an API Call com método
POST(ouPUT), URL/links(ou/links/{linkId}), cabeçalhoContent-Type: application/jsone um dos corpos JSON acima; o módulo autentica com a sua conexão CodeQR. - Zapier: o app CodeQR oferece os triggers New Link, New Page e New QR Code, as ações Create a Link, Create a QR Code, Delete Link e Delete QR Code, e as buscas Retrieve Link e Retrieve a QR Code. Create a Link não tem campo de regras; para definir regras, chame a API por um passo Webhooks by Zapier (Custom Request) ou Code com um dos corpos acima.
- Pluga: baseada em webhooks; chame a API por um passo HTTP.
- Webhooks: os payloads de
link.createdelink.updatedcontêm o objeto do link com suasrules(mesmo formato da resposta da API). Os eventoslink.clickedeqrcode.scannedtrazem o clique comurligual ao destino para o qual o visitante foi de fato enviado — a URL da regra ou a variante da divisão — além do objeto do link. Use-os para espelhar mudanças de regra e cliques por destino nos seus sistemas.
Como verificar
curl -s https://api.codeqr.io/links/cmswk759f0001j41i0vj1vmfq \ -H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" | python3 -m json.tool | grep -A 12 '"rules"' curl -sI -A "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) Safari/604.1" https://go.example.com/baixe-o-app | grep -i location # location: https://apps.apple.com/br/app/example-app/id1234567890
As mudanças valem na requisição seguinte — não há atraso de cache depois de um salvamento bem-sucedido.
Solução de problemas
403 "Smart rules are available on the Business plan and above"
O plano do workspace é Free, Starter ou Pro. Toda requisição com rules não vazio falha, inclusive atualizações de links que já têm regras. Envie "rules": null (ou omita o campo) ou faça upgrade.
400 com error.code "unprocessable_entity"
Validação de schema. A mensagem nomeia a regra que falhou pelo índice (rules[2]) e o campo. Compare com a tabela acima; os mais frequentes são pesos que não somam 100, condição incompleta e regra só de divisão fora da última posição.
As regras foram salvas mas nada combina
O valor não é o que a requisição carrega: mobile em vez de iOS/Android, Brasil em vez de BR, BR-SP em vez de SP, uma URL completa em vez de um domínio puro no referrer, um UTM que está na URL de destino em vez de no link curto. Veja a referência.
405 na atualização
Use PUT /links/{linkId} (e PUT /qrcodes/{qrcodeId}); PATCH não é suportado.
O utm_source do link na resposta é null embora minha regra use utm_source
Os campos utm_* do objeto do link descrevem a URL de destino. As regras leem a query string da requisição recebida no link curto; são campos independentes.