logo
APIIntegraçõ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.

  • attribute — Tipo: enum · Significado: device, country, city, region, continent, language, referrer, utm_source, utm_medium, utm_campaign, utm_term, utm_content
  • operator — Tipo: enum · Significado: equals, not_equals
  • value — Tipo: string 1–190 · Significado: comparada por inteiro e sem diferenciar maiúsculas com o que a requisição carrega
  • url — Tipo: string (URL) · Significado: destino do tráfego que combina — ou
  • split — 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[] com url e weight
  • Todo o tráfego — Na API: uma regra sem attribute, operator, value
  • Valor de dispositivo macOS** — Na API: "Mac OS" (também iOS, Android, Windows, Linux)
  • Botão Regras inteligentes desligado — Na API: "rules": null

Endpoints que aceitam rules

  • POST /links — Uso: criar um link com regras
  • PUT /links/{linkId} — Uso: substituir as regras de um link (PATCH não é suportado — 405)
  • POST /links/bulk — Uso: criar vários links; cada item aceita rules
  • POST /qrcodes — Uso: criar um QR Code dinâmico do tipo url com regras
  • PUT /qrcodes/{qrcodeId} — Uso: substituir as regras de um QR Code
  • POST /qrcodes/bulk — Uso: 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

  • 401error.code: unauthorized · error.message: Unauthorized: Login required. · Causa: chave de API ausente ou inválida
  • 403error.code: forbidden · error.message: Smart rules are available on the Business plan and above. Upgrade to Business to use this feature. · Causa: rules não vazio vindo de um workspace Free, Starter ou Pro
  • 403error.code: forbidden · error.message: Smart rules can only be used on dynamic QR codes. · Causa: static: true com regras
  • 400error.code: unprocessable_entity · error.message: custom: rules[0]: Split weights must add up to 100 · Causa: soma dos pesos ≠ 100
  • 400error.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
  • 400error.code: unprocessable_entity · error.message: custom: rules[0]: A rule condition needs attribute, operator and value together · Causa: condição incompleta
  • 400error.code: unprocessable_entity · error.message: custom: rules[0]: A rule needs either a destination url or a traffic split, never both · Causa: url e split na mesma regra
  • 400error.code: unprocessable_entity · error.message: custom: rules[0]: A rule without a condition must split traffic · Causa: regra de todo o tráfego com url
  • 400error.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 para operator
  • 400error.code: unprocessable_entity · error.message: custom: rules[0].url: Invalid URL · Causa: destino não é uma URL
  • 400error.code: unprocessable_entity · error.message: too_big: rules[0].value: String must contain at most 190 character(s) · Causa: valor longo demais
  • 400error.code: unprocessable_entity · error.message: too_big: rules: Array must contain at most 20 element(s) · Causa: mais de 20 regras
  • 405error.code: — · error.message: — · Causa: PATCH /links/{id}; use PUT
  • 422error.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 (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