Uma API de encurtador de URL é uma das integrações menores no backlog de uma equipe de engenharia típica. Três endpoints, um header de autenticação, um payload JSON. A página da documentação promete a primeira chamada em cinco minutos. Então o tráfego de produção chega, a lógica de retry cria links duplicados, o painel se enche de variantes /foo-1, /foo-2, /foo-3 do mesmo destino, e alguém abre um ticket.
Este post percorre a integração de verdade. Autenticação, a primeira chamada, os quatro endpoints que cobrem a maioria dos casos de uso, idempotência, tratamento de erro, limites de taxa, e as pegadinhas de produção que o guia rápido de cinco minutos pula. Exemplos de código em TypeScript, Python, Go, Ruby e PHP - as três primeiras pelos SDKs oficiais (@elido/sdk, elido-python, github.com/elido/elido-go), as duas últimas por clientes HTTP simples.
Pré-requisitos
Entre no painel, navegue até /dashboard/api-keys, e crie uma chave de API (ela começa com elido_). Tokens são escopados por workspace - um token emitido no workspace A não pode criar links no workspace B. Tokens de usuário-máquina (para sistemas de CI, ferramentas internas, integração máquina-a-máquina) são criados em /dashboard/machine-users e rotacionam independentemente das chaves pessoais. Os dois tipos carregam um papel de workspace pré-definido (viewer, editor ou admin) em vez de escopos por endpoint, então dê a um job de CI o papel editor se ele só cria links. O guia sobre permissões de chaves de API lista o que cada papel pode acessar, incluindo por que alterações em webhooks exigem admin.
A URL base é https://api.elido.app/v1. Os domínios de redirecionamento (f.elido.me, s.elido.me, b.elido.me) são separados da superfície da API. Seus links curtos resolvem no domínio de redirecionamento; a API serve para criar, modificar e ler os links.
A especificação OpenAPI é publicada em https://elido.app/openapi.json e segue o OpenAPI 3.1. Os SDKs oficiais são gerados a partir dessa especificação e republicados a cada lançamento da API; você também pode gerar seu próprio cliente em qualquer linguagem compatível com OpenAPI.
A primeira chamada
Crie um link curto a partir da URL de destino. Cinco linhas em TypeScript:
import { Elido } from "@elido/sdk";
const elido = new Elido({ token: process.env.ELIDO_TOKEN! });
const link = await elido.links.create({
destinationUrl: "https://shop.example.com/spring-sale",
});
console.log(link.shortUrl); // https://s.elido.me/abc123
Python:
from elido import Elido
client = Elido(token=os.environ["ELIDO_TOKEN"])
link = client.links.create(
destination_url="https://shop.example.com/spring-sale",
)
print(link.short_url) # https://s.elido.me/abc123
Go:
import "github.com/elido/elido-go/v2/elido"
client := elido.NewClient(elido.WithToken(os.Getenv("ELIDO_TOKEN")))
link, err := client.Links.Create(ctx, &elido.LinkCreateInput{
DestinationURL: "https://shop.example.com/spring-sale",
})
if err != nil {
return fmt.Errorf("create link: %w", err)
}
fmt.Println(link.ShortURL)
Ruby (sem SDK oficial - usando net/http):
require "net/http"
require "json"
uri = URI("https://api.elido.app/v1/links")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['ELIDO_TOKEN']}"
req["Content-Type"] = "application/json"
req.body = { destination_url: "https://shop.example.com/spring-sale" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
link = JSON.parse(res.body)
puts link["short_url"]
PHP (Guzzle):
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.elido.app/v1/']);
$res = $client->post('links', [
'headers' => ['Authorization' => 'Bearer ' . getenv('ELIDO_TOKEN')],
'json' => ['destination_url' => 'https://shop.example.com/spring-sale'],
]);
$link = json_decode((string) $res->getBody(), true);
echo $link['short_url'];
As cinco produzem o mesmo resultado. O corpo da resposta contém a URL curta, o ID canônico do link, o ID do workspace, e o timestamp de criação. O slug - abc123 no exemplo acima - é gerado pelo servidor a menos que você passe slug na requisição. O alfabeto do slug é base62 ([0-9A-Za-z]); o comprimento padrão é seis caracteres.
Os quatro endpoints que você realmente vai usar
A API tem mais de quatro endpoints, mas a maioria das integrações fica dentro desse conjunto.
Criar um link
POST /v1/links aceita a URL de destino mais campos opcionais:
slug- um slug que você escolhe (precisa ser único no domínio).domain_id- para links de domínio personalizado; em/v1/links, o domínio curto padrão do seu plano é usado se omitido. O caminho com escopo de workspace/v1/workspaces/{workspace_id}/linksexige esse campo.title- um rótulo exibido no painel.tags- um array de strings livres para organização.expires_at- timestamp RFC 3339 após o qual o link retorna 410 Gone.redirect_status-301,302(o padrão) ou307.password- ainda não aceito na criação; defina-o com umPATCHlogo depois, e o redirecionamento exibirá uma página de senha antes de encaminhar.utmemetadata- planejados. Hoje, coloque os parâmetros UTM diretamente emdestination_urle mantenha suas próprias chaves de junção emtags.
O slug personalizado é o campo que morde as equipes em produção. Se você passa um slug já em uso por outro link no mesmo domínio, a API retorna 409 Conflict. O tratador de retry ingênuo que acrescenta um contador (my-slug-1, my-slug-2) produz o problema de link duplicado descrito na abertura. O comportamento de retry correto está descrito na seção de idempotência abaixo.
Ler um link
GET /v1/links/{id} retorna o registro completo do link, incluindo short_url e toda a configuração. As contagens de cliques não estão no registro do link; elas vêm dos endpoints de analytics abaixo. O ID do link é o identificador canônico - slugs podem mudar, IDs não.
GET /v1/links?host=…&tags=…&limit=… lista links no workspace com filtros. A paginação é baseada em cursor; next_cursor na resposta é opaco e volta como o parâmetro de query cursor na próxima requisição.
Atualizar um link
PATCH /v1/links/{id} aceita os mesmos campos que a criação. As atualizações mais comuns: mudar a URL de destino (útil para rotação de campanha sem reimprimir QR codes), mudar tags, estender expires_at. O slug é alterado pelo mesmo PATCH, enviando um novo slug. O slug antigo deixa de resolver imediatamente; um endpoint de renomeação dedicado que mantém um 301 do slug antigo por um período de retenção está planejado, não foi criado.
Excluir um link
DELETE /v1/links/{id} faz exclusão reversível e retorna 204 No Content. O link deixa de redirecionar e desaparece das chamadas de listagem e leitura. Uma visão de lixeira com endpoint de restauração e uma janela de 90 dias antes da exclusão permanente está planejada; hoje não há uma chamada de API que traga um link excluído de volta.
Chaves de idempotência
Toda requisição mutante - POST, PATCH, DELETE - aceita um header Idempotency-Key. O valor do header é uma string opaca de até 255 caracteres; o servidor armazena o corpo da resposta e o código de status por 24 horas, chaveado em (workspace_id, idempotency_key), e retorna a resposta armazenada se a mesma chave for apresentada novamente.
Os SDKs oficiais geram chaves de idempotência automaticamente quando não fornecidas. Você pode sobrescrever:
const link = await elido.links.create(
{ destinationUrl: "https://shop.example.com/spring-sale" },
{ idempotencyKey: "order-12345-link" },
);
O caso de uso é um loop de retry. Se seu job cria um link como parte do processamento de um pedido upstream, gere a chave de idempotência a partir do ID do pedido. Uma nova tentativa do mesmo job vê a mesma chave, acerta o cache de idempotência, e retorna o link criado originalmente em vez de produzir um segundo.
A principal pegadinha: o cache de idempotência vive por 24 horas, não para sempre. Uma nova tentativa no terceiro dia de um job travado vai criar um novo link. Se a integração roda em lotes de vários dias, armazene o ID do link retornado pela primeira criação bem-sucedida e consulte-o antes de emitir novamente.
Uma segunda pegadinha: idempotência é por workspace. A mesma chave em dois workspaces cria dois links. Essa é a semântica correta para uma API multi-workspace, mas pode surpreender equipes que assumem que a chave é globalmente única.
Tratamento de erro
A API retorna códigos de status HTTP padrão mais um corpo de erro estruturado:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Workspace rate limit of 100 req/s exceeded. Retry after 1 second.",
"request_id": "req_01HXYZAB123",
"retry_after": 1
}
}
Os códigos que você verá com mais frequência:
400 invalid_request- falha de validação do payload. O campomessagelista os campos específicos. Não tente novamente; corrija o payload.401 unauthorized- token ausente ou inválido. Não tente novamente sem rotacionar o token.403 forbidden- o papel do token não permite a ação (uma chaveviewernão pode criar links). Verifique o papel da chave em/dashboard/api-keys.404 not_found- o recurso não existe ou o token não tem acesso a ele (retornamos 404 em vez de 403 para evitar vazar a existência do recurso a chamadores não autorizados).409 conflict- slug já em uso, ou edição simultânea detectada (PATCH em uma versão desatualizada). Busque novamente e tente de novo.429 rate_limit_exceeded- recue conforme o valor deretry_after.500 internal_server_error- falha do lado do servidor. Seguro para tentar novamente com a mesma chave de idempotência.502 bad_gateway,503 service_unavailable,504 gateway_timeout- problemas de infraestrutura transitórios. Recue e tente novamente.
Os SDKs oficiais implementam backoff exponencial com jitter para 429, 500, 502, 503 e 504. Eles não tentam novamente em 400, 401, 403, 404 ou 409 - esses são erros de programação ou conflitos de lógica de negócio, não falhas transitórias. Clientes HTTP personalizados devem seguir o mesmo padrão; tentar novamente um 400 com o mesmo payload não vai produzir um resultado diferente.
O request_id no corpo do erro é o campo a incluir em tickets de suporte. Podemos rastrear qualquer requisição a partir desse ID pelo log de auditoria, pelo log da aplicação, e pelas métricas da plataforma - e não conseguimos rastrear uma requisição sem ele.
Limites de taxa
Os limites de taxa publicados são 100 requisições por segundo por workspace no Pro, 500 no Business, e um limite negociado no Enterprise. O nível gratuito é 10 req/s.
O estado do limite de taxa é exposto em três headers de resposta em toda resposta da API:
X-RateLimit-Limit- o limite por segundo atual.X-RateLimit-Remaining- requisições restantes no segundo atual.X-RateLimit-Reset- timestamp Unix de quando o bucket é reiniciado.
O limite de 100/s é uma implementação de token bucket com capacidade de burst de 200 - o que significa que você pode emitir 200 requisições de uma vez se o bucket estiver cheio, e então se estabilizar na taxa sustentada de 100/s. A maioria dos jobs de criação de link curto cabe confortavelmente no burst; integrações pesadas em analytics que percorrem eventos de clique históricos se beneficiam da folga do nível Pro.
Para operações em massa, o endpoint POST /v1/links/bulk aceita até 100 links por requisição e conta como uma única unidade de limite de taxa. Esse é o endpoint certo para qualquer job que crie mais de cem links de uma vez. Para o tratamento mais profundo sobre ritmo contra o token bucket, escolher quais códigos de status tentar novamente, e como as chaves de idempotência evitam que novas tentativas dupliquem links, veja limites de taxa, retries e idempotência em produção.
O que os SDKs fazem que o HTTP simples não faz
Os SDKs oficiais entregam quatro coisas que se pagam rapidamente:
- Retry automático com backoff para os códigos de status que permitem nova tentativa.
- Geração de chave de idempotência quando não fornecida explicitamente.
- Erros tipados para que você possa fazer
catch (err) { if (err instanceof ElidoRateLimitError) { … } }em vez de analisar JSON em blocos catch. - Iteradores de paginação para que endpoints de listagem exponham iteradores assíncronos ou geradores em vez de exigir manipulação manual de cursor.
O SDK de Go também expõe o cliente HTTP subjacente para instrumentação - útil se você quer conectá-lo à sua configuração de tracing existente. A página do recurso API + SDKs do repositório cobre a superfície completa; a referência da API é publicada em /docs/api-reference.
Acesso a analytics
Os endpoints de analytics são somente leitura e vivem sob /v1/workspaces/{id}/analytics/; o guia da API de analytics de links lista todos os relatórios, seus parâmetros e o formato de suas respostas. As consultas mais comuns:
GET .../clicks/recent?from=…&to=…- cliques individuais, do mais recente para o mais antigo, paginados comnext_cursor. Útil para pipelines de exportação.GET .../timeseries?from=…&to=…&interval=day- contagens de clique agrupadas para um intervalo de tempo;intervaléhourouday, etzdefine o fuso horário dos agrupamentos.GET .../breakdown/country?from=…&to=…- detalhamento geográfico.GET .../breakdown/referrer?from=…&to=…- detalhamento por referrer.
Os outros relatórios são summary, links/top, os demais detalhamentos (host, device, browser, destination) e as listas de mais acessados (top-countries, top-regions, top-cities, top-referrers, top-destinations). from e to são datas em YYYY-MM-DD e to é exclusivo; adicione link_id para restringir qualquer relatório a um link, e limit para definir o tamanho dos detalhamentos e das listas de mais acessados.
O feed de eventos de clique brutos é o maior. Um workspace com 10 milhões de cliques por mês produz cerca de 600MB de dados de evento bruto em JSON por mês. Para exportações nessa escala, o guia de exportação de analytics cobre o mecanismo de exportação em massa que contorna o envelope JSON e transmite diretamente do data warehouse de analytics.
Webhooks para eventos de link
Webhooks são o inverso do polling - em vez de você perguntar à API o que mudou, a API entrega eventos de link e domínio ao seu endpoint. Configure em /dashboard/webhooks:
await elido.webhooks.create({
url: "https://your-app.example/webhooks/elido",
events: ["link.created", "link.updated", "link.expired"],
secret: process.env.WEBHOOK_SIGNING_SECRET,
});
Um evento click.created por clique está no roadmap, mas ainda não disponível, então hoje os dados de clique vêm dos endpoints de analytics. Cada entrega inclui um header X-Elido-Signature (também enviado como X-Webhook-Signature) com o valor v1=<hex>: um HMAC-SHA256, chaveado com o segredo do seu endpoint, sobre o valor de X-Webhook-Timestamp, um ponto e o corpo bruto da requisição. Verifique a assinatura antes de processar - sem isso, qualquer chamador pode postar no seu endpoint de webhook e se passar pelo Elido.
A semântica de entrega é at-least-once: uma entrega que falha é tentada novamente com backoff de minutos, com três tentativas no total por padrão. Para o formato detalhado e o comportamento de retry, o post webhooks vs polling compara os dois padrões de integração.
Um exemplo prático: automação de campanha
A integração que motiva a maior parte da adoção da API se parece com isto. Sua automação de marketing cria uma campanha no Customer.io ou no HubSpot. Um hook dispara quando a campanha é publicada. Seu manipulador cria o link curto, o anexa ao registro da campanha, e o envia de volta para a ferramenta de gestão de campanha para substituir no template de e-mail.
Em TypeScript:
import { Elido } from "@elido/sdk";
const elido = new Elido({ token: process.env.ELIDO_TOKEN! });
export async function onCampaignPublished(campaign: Campaign) {
const link = await elido.links.create(
{
destinationUrl: campaign.destinationUrl,
tags: [
"campaign",
`campaign:${campaign.id}`,
`batch:${campaign.batchId}`,
campaign.channel,
],
},
{
idempotencyKey: `campaign-${campaign.id}-link`,
},
);
await campaignStore.update(campaign.id, { shortUrl: link.shortUrl });
return link;
}
A chave de idempotência é derivada do ID da campanha. Se o hook de campanha publicada disparar duas vezes (isso acontece - entregas de webhook são at-least-once), a segunda chamada retorna o mesmo link sem criar uma duplicata. As tags campaign: e batch: carregam suas próprias chaves de junção para que você possa correlacionar os eventos de clique do Elido de volta à campanha; um campo metadata dedicado para isso está planejado. Os parâmetros UTM pertencem à própria campaign.destinationUrl até que o campo utm seja lançado.
Para atribuição de campanha de ponta a ponta com templates de UTM e encaminhamento de conversão, o conteúdo principal de rastreamento de UTM percorre o pipeline completo.
O que ainda não está na API
Duas coisas comumente perguntadas, atualmente não disponíveis:
- Um único GET de analytics de link que retorna todos os detalhamentos em uma chamada. O modelo atual exige chamadas separadas para cliques, país, referrer, dispositivo e série temporal. A agregação está no roadmap; por enquanto, faça as requisições em paralelo a partir do seu próprio código.
- Replay de webhook a partir da API. O painel expõe o histórico de entrega de webhook e aceita replay; a API ainda não. Isso também está no roadmap.
Se um recurso está na especificação OpenAPI, ele é suportado. Se está neste post mas não na especificação, trate-o como planejado em vez de garantido.
Leitura relacionada
- Smart links explicados - o conteúdo principal do cluster de recursos; cobre como o motor de redirecionamento resolve um link na borda.
- Webhooks vs polling para rastreamento de clique - quando usar qual padrão de integração.
- Rastreamento de conversão server-side via links curtos - estendendo a API para o fluxo de encaminhamento de conversão.
- Importação em massa de campanhas a partir do Google Sheets - um exemplo prático do endpoint em massa.
- API do encurtador de URL: limites de taxa, retries, idempotência - fortalecendo a integração para tráfego de produção.
- Permissões de chaves de API para ferramentas de links - chaves vinculadas ao workspace, limites de papel e rotação.
- API gratuita de encurtador de URL: exemplos de código que rodam - a chamada de criação em curl, JavaScript, Python e Go, e o que os níveis gratuitos limitam.
- API de analytics de links: consulte estatísticas de cliques com uma chave de API - todos os relatórios, seus parâmetros de consulta e um script diário para o Slack.
- Passo a passo operacional: o guia do servidor MCP para conectar a superfície de API do Elido ao Claude, Cursor e outros clientes compatíveis com MCP.
- Superfície de produto:
/features/api-sdkse/solutions/developers.
Experimente Elido
Cole uma URL, obtenha um link curto
Sem cadastro. O link vive 30 dias. Cadastre-se para mantê-lo para sempre.
Grátis, sem necessidade de registo · 2 por dia