logo
APIAutomações

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.

Avatar for undefined
CodeQR Team
Equipe de Conteúdo

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 rules não vazio é recusada com 403 forbidden.
  • URL base da API: https://api.codeqr.io. Autenticação: Authorization: Bearer <chave de API> — crie uma chave em ConfiguraçõesChaves 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 um linkId existente.
  • 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.

JSONTipoSignificado

attribute

enum

device, country, city, region, continent, language, referrer, utm_source, utm_medium, utm_campaign, utm_term, utm_content

operator

enum

equals, not_equals

value

string 1–190

comparada por inteiro e sem diferenciar maiúsculas com o que a requisição carrega

url

string (URL)

destino do tráfego que combina — ou

split

array de 2–4 { "url", "weight" }

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:

No appNa API

Dispositivo / País / Cidade / Região (estado) / Continente / Idioma / Referenciador

device / country / city / region / continent / language / referrer

Origem UTM / Mídia UTM / Campanha UTM / Termo UTM / Conteúdo UTM

utm_source / utm_medium / utm_campaign / utm_term / utm_content

é / não é

equals / not_equals

URL de destino (de uma regra)

url

Dividir tráfego (teste A/B) com URL da variante e Peso da variante (%)

split[] com url e weight

Todo o tráfego

uma regra sem attribute, operator, value

Valor de dispositivo macOS

"Mac OS" (também iOS, Android, Windows, Linux)

Botão Regras inteligentes desligado

"rules": null

Endpoints que aceitam rules

Método e caminhoUso

POST /links

criar um link com regras

PUT /links/{linkId}

substituir as regras de um link (PATCH não é suportado — 405)

POST /links/bulk

criar vários links; cada item aceita rules

POST /qrcodes

criar um QR Code dinâmico do tipo url com regras

PUT /qrcodes/{qrcodeId}

substituir as regras de um QR Code

POST /qrcodes/bulk

criar vários QR Codes; cada item aceita rules

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 forbiddenSmart 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

HTTP`error.code``error.message`Causa

401

unauthorized

Unauthorized: Login required.

chave de API ausente ou inválida

403

forbidden

Smart rules are available on the Business plan and above. Upgrade to Business to use this feature.

rules não vazio vindo de um workspace Free, Starter ou Pro

403

forbidden

Smart rules can only be used on dynamic QR codes.

static: true com regras

400

unprocessable_entity

custom: rules[0]: Split weights must add up to 100

soma dos pesos ≠ 100

400

unprocessable_entity

custom: rules: A rule without a condition matches all traffic, so it must be the last one

regra só de divisão fora da última posição

400

unprocessable_entity

custom: rules[0]: A rule condition needs attribute, operator and value together

condição incompleta

400

unprocessable_entity

custom: rules[0]: A rule needs either a destination url or a traffic split, never both

url e split na mesma regra

400

unprocessable_entity

custom: rules[0]: A rule without a condition must split traffic

regra de todo o tráfego com url

400

unprocessable_entity

invalid_enum_value: rules[0].attribute: Invalid enum value. Expected 'device' | 'country' | … , received 'browser'

atributo desconhecido; mesmo padrão para operator

400

unprocessable_entity

custom: rules[0].url: Invalid URL

destino não é uma URL

400

unprocessable_entity

too_big: rules[0].value: String must contain at most 190 character(s)

valor longo demais

400

unprocessable_entity

too_big: rules: Array must contain at most 20 element(s)

mais de 20 regras

405

PATCH /links/{id}; use PUT

422

unprocessable_entity

Malicious URL detected

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 (ou PUT), URL /links (ou /links/{linkId}), cabeçalho Content-Type: application/json e 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.created e link.updated contêm o objeto do link com suas rules (mesmo formato da resposta da API). Os eventos link.clicked e qrcode.scanned trazem o clique com url igual 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.

Artigos relacionados