logo
API

Crie seu primeiro link curto com a API da CodeQR

Crie, leia, atualize e liste links curtos com a API REST da CodeQR — requisições e respostas reais em curl, limites por plano, externalId e o SDK.

Avatar for undefined
CodeQR Team
Equipe de Conteúdo

Ao fim deste guia você terá criado um link curto pela linha de comando, lido o link de volta, trocado o destino, listado seus links com paginação e saberá os limites que o seu plano aplica. Toda requisição abaixo rodou num workspace real em 2026-08-17; só o domínio foi trocado por go.example.com.

Disponibilidade

  • Plano: todos os planos. Requisições por minuto por chave — Free 60, Starter 100, Pro 500, Business 1.000, Scale 10.000.
  • Onde: URL base https://api.codeqr.io, chave em ConfiguraçõesChaves de API. Referência de endpoints em docs.codeqr.io; QR codes têm guia próprio, Crie QR Codes com a API, o MCP e automações.

Antes de começar

  • Uma chave de API com Links → Write (ou Acesso Total). Veja Crie uma chave de API e escolha as permissões.
  • A chave decide o workspace. Não há ID de workspace para enviar; projectSlug ou projectId na query string são ignorados quando você autentica com uma chave.
  • Envie JSON com Content-Type: application/json. As respostas são JSON; erros vêm como { "error": { "code", "message", "doc_url" } }.
  • Atualizações usam PUT, não PATCH (PATCH /links/{id} responde 405).

Passos

  1. Crie um link. domain e key são opcionais: sem eles o link sai no domínio padrão do workspace com uma chave aleatória de 7 caracteres.
curl -X POST https://api.codeqr.io/links \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/summer-sale?utm_source=newsletter&utm_medium=email&utm_campaign=summer","domain":"go.example.com","key":"docs-summer","comments":"Created from the help-center test"}'

Resposta 200 (recortada aos campos que você vai usar; o objeto completo está na referência):

{
  "id": "cmsxh367q0003wu8tzav2adsp",
  "domain": "go.example.com",
  "key": "docs-summer",
  "url": "https://example.com/summer-sale?utm_source=newsletter&utm_medium=email&utm_campaign=summer",
  "shortLink": "https://go.example.com/docs-summer",
  "qrCode": "https://api.codeqr.io/qr?url=https://go.example.com/docs-summer?qr=1",
  "archived": false,
  "expiresAt": null,
  "externalId": null,
  "utm_source": "newsletter",
  "utm_medium": "email",
  "utm_campaign": "summer",
  "tags": [],
  "comments": "Created from the help-center test",
  "clicks": 0,
  "createdAt": "2026-08-17T16:53:20.822Z"
}

Guarde o id — é o que toda outra chamada usa. Os utm_* são lidos da URL de destino; enviá-los como campos separados não faz nada.

  1. Leia de volta por domínio e chave, ou por id:
curl "https://api.codeqr.io/links/info?domain=go.example.com&key=docs-summer" \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••"

curl https://api.codeqr.io/links/cmsxh367q0003wu8tzav2adsp \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••"

As duas devolvem o mesmo objeto de link; clicks cresce conforme as pessoas abrem o link curto.

  1. Troque o destino com PUT e só os campos que quer mudar:
curl -X PUT https://api.codeqr.io/links/cmsxh367q0003wu8tzav2adsp \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/summer-sale-v2","comments":"updated via PUT"}'

Resposta 200 com "url": "https://example.com/summer-sale-v2" e um novo updatedAt. O link curto https://go.example.com/docs-summer continua funcionando e agora redireciona para a nova URL. Se a nova URL não trouxer parâmetros UTM, os utm_* anteriores ficam no link até uma URL com novos parâmetros ser definida.

  1. Liste e pesquise. page começa em 1; pageSize vai até 100 (padrão 100); sortBy aceita createdAt, clicks, lastClicked.
curl "https://api.codeqr.io/links?search=docs-&page=1&pageSize=2&sortBy=createdAt" \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••"

Devolve um array de objetos de link (cada um traz também user e tags). Para contar em vez de listar: GET /links/count (acrescente tagIds=<id> para contar uma tag).

  1. Torne a criação idempotente com externalId. Envie o id do seu próprio registro na criação; consulte depois com o prefixo ext_; uma segunda criação com o mesmo externalId é recusada em vez de duplicada:
curl -X POST https://api.codeqr.io/links \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/products/42","domain":"go.example.com","externalId":"row-42"}'
# → 200, "key": "3FSQv8g", "externalId": "row-42"

curl "https://api.codeqr.io/links/info?externalId=ext_row-42" \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••"
# → 200, o mesmo link

# o mesmo externalId de novo → 409 {"error":{"code":"conflict","message":"A link with this externalId already exists."}}
  1. Apague com DELETE /links/{id}200 {"id": "…"}. Um link curto apagado para de redirecionar; os cliques passados ficam nos totais do workspace.

Limites de requisições e cabeçalhos

Toda resposta autenticada traz x-ratelimit-limit, x-ratelimit-remaining e x-ratelimit-reset (um timestamp Unix em milissegundos). Acima do limite a API responde 429 com Too many requests.; espere o próximo minuto. O cabeçalho retry-after nessas respostas traz o mesmo timestamp, não uma quantidade de segundos — não durma pelo valor dele.

Use o SDK em vez do curl

O SDK em TypeScript envolve os mesmos endpoints:

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/summer-sale', domain: 'go.example.com' });
console.log(link.shortLink);

Não há SDK oficial em Python, Go ou PHP; use a API HTTP diretamente nessas linguagens.

Verifique se funcionou

  1. Abra https://go.example.com/docs-summer (o seu link curto) num navegador — ele redireciona para o destino que você definiu.
  2. Dois a três minutos depois, GET /links/info?domain=…&key=… mostra "clicks": 1, e o link aparece em Links no painel com a mesma contagem.
  3. Em ConfiguraçõesChaves de API, a coluna Último uso da chave mostra um horário recente.

Solução de problemas

PUT funciona, mas PATCH devolve 405

PUT atualiza um link. Troque o verbo; o corpo é o mesmo JSON parcial.

tagNames devolve 400 com um erro longo de banco de dados

Enviar tagNames no POST /links falha hoje mesmo quando a tag existe (o texto do erro começa com Invalid prisma.link.create() invocation). Envie tagIds — pegue os ids em GET /tags — ou anexe a tag depois com PUT /links/{id} e tagIds. tagNames com um nome inexistente responde Invalid tagNames detected: <nome>.

GET /links/count?search=… devolve 500

O endpoint de contagem falha combinado com search. Conte sem search, filtre por tagIds, ou liste com pageSize e conte do seu lado.

A resposta não tem workspaceId e meu código esperava um

Links trazem projectId — esse é o id do workspace. Chaves são presas a um workspace, então você nunca o envia.

Recebo 401 "Unauthorized: Login required." mesmo enviando a chave

O cabeçalho Authorization não chegou à API — em geral o nome do cabeçalho foi digitado errado ou um proxy o removeu. Se você enviou o cabeçalho sem o prefixo Bearer , a resposta é um texto puro Authorization header misconfigured. Did you forget to add 'Bearer '?. Veja Corrija erros da API da CodeQR: 401, 403, 404, 409 e 429.

Artigos relacionados