API · v1
Trocar o link de uma campanha pela API
Liste os Instagrams e as campanhas da sua conta do DM Link e troque pra onde o link de uma campanha aponta, a partir de qualquer outro sistema.
Como funciona
Quando uma campanha do DM Link manda o link no direct, ela não manda o endereço final direto. Ela manda um link rastreado do próprio DM Link, no formato https://dmlink.app/r/abc123, que redireciona pro destino configurado.
A API troca esse destino. Por isso:
- quem receber o direct daqui pra frente cai no destino novo;
- quem recebeu o direct antes e clicar depois também cai no destino novo;
- a campanha continua rodando igual, sem ninguém mexer nela.
O código no fim do link rastreado (abc123) é o slug. É ele que identifica qual link trocar. Um uso típico: um bot que gerencia grupos de WhatsApp troca o link pro grupo seguinte quando o atual lota.
1. Pegar a chave de API
- Entre no DM Link como dono ou administrador da conta.
- Vá em Configurações → Chaves de API.
- Em “Para que você vai usar esta chave?”, escreva um nome só para você reconhecer a chave depois (ex.: meu sistema de grupos do WhatsApp) e clique em Criar chave.
- Copie a chave na hora. Ela começa com
dml_e só aparece uma vez. Depois disso nem o DM Link consegue mostrar de novo.
Na mesma tela você vê as chaves ativas, desativa qualquer uma (ela para de funcionar na hora) e acompanha o histórico das últimas trocas de link feitas pela API.
Uma conta, uma chave, todos os Instagrams conectados nela
- A chave é da conta do DM Link em que foi criada.
- Ela enxerga e troca links de todos os Instagrams conectados nessa conta (até 3 no Infinity). Não precisa de uma chave por Instagram.
- Ela não enxerga outras contas do DM Link. Se o Instagram que você quer está conectado em outra conta, ou conecta ele nesta, ou cria uma chave naquela conta.
Pra conferir se a chave é da conta certa, chame GET /api/v1/instagram-accounts: se o Instagram que você procura não aparecer na lista, a chave é de outra conta.
2. Endereço da API e autenticação
Endereço base
https://dmlink.app/api/v1Mande a chave em toda chamada
Authorization: Bearer dml_SUA_CHAVETambém é aceito X-API-Key: dml_SUA_CHAVE. As respostas são sempre JSON: {"success": true, "data": ...} ou {"success": false, "error": {"code": "...", "message": "..."}}.
| Método | Caminho | Pra que serve |
|---|---|---|
GET | /api/v1/instagram-accounts | Listar os Instagrams conectados na conta |
GET | /api/v1/campaigns | Listar as campanhas e os links de cada uma, de todos os Instagrams |
GET | /api/v1/campaigns?instagram=@usuario | Listar só as campanhas de um Instagram |
GET | /api/v1/links/{slug} | Ver pra onde um link aponta agora |
PATCH (ou PUT) | /api/v1/links/{slug} | Trocar o destino de um link |
3. Listar os Instagrams da conta
Devolve os Instagrams conectados na conta da chave, na ordem em que foram conectados. Use pra montar a escolha "qual Instagram".
curl https://dmlink.app/api/v1/instagram-accounts \
-H "Authorization: Bearer $DMLINK_API_KEY"Resposta
{
"success": true,
"data": [
{
"id": "cm9z8y7x6w5v4u",
"username": "mybrand",
"name": "My Brand",
"needsReconnect": false,
"campaignCount": 1
},
{
"id": "cm1q2w3e4r5t6y",
"username": "another.profile",
"name": null,
"needsReconnect": false,
"campaignCount": 2
}
]
}| Campo | O que é |
|---|---|
id | Identificador do Instagram no DM Link (não muda). |
username | O @ do Instagram, sem o @. |
name | Nome do perfil (pode vir null). |
needsReconnect | true quando a Meta derrubou a conexão: as campanhas desse Instagram param de responder até o dono reconectar no DM Link. A troca de link continua funcionando. |
campaignCount | Quantas campanhas esse Instagram tem (ativas e pausadas). |
4. Listar as campanhas de um Instagram
Devolve as campanhas, das mais novas pras mais antigas, com os links rastreados de cada uma e de qual Instagram cada uma é. Use pra descobrir o slug do link que você vai trocar.
- Sem o
?instagram=: vêm as campanhas de todos os Instagrams da conta. - Com o
?instagram=: só as daquele Instagram. Aceita ousername(com ou sem@, maiúscula ou minúscula) ou oiddo passo 3. Se o Instagram não estiver na conta da chave, responde404 not_found. - As duas listas só trazem Instagrams conectados. Um Instagram que o dono desconectou some das duas até ser reconectado.
Sobre os links de cada campanha:
position: 1é o link do botão principal da campanha.position: 2é o segundo botão, quando existe.- A ordem é estável: o mesmo link tem sempre a mesma posição, mesmo depois de trocar o destino.
curl "https://dmlink.app/api/v1/campaigns?instagram=mybrand" \
-H "Authorization: Bearer $DMLINK_API_KEY"Resposta
{
"success": true,
"data": [
{
"id": "cm1a2b3c4d5e6f",
"name": "VIP group",
"active": true,
"instagram": { "id": "cm9z8y7x6w5v4u", "username": "mybrand" },
"links": [
{
"slug": "abc123",
"position": 1,
"label": "Primary campaign link",
"destinationUrl": "https://chat.whatsapp.com/CURRENT_GROUP",
"trackedUrl": "https://dmlink.app/r/abc123",
"updatedAt": "2026-10-02T12:00:00.000Z"
}
]
}
]
}5. Ver o destino atual de um link
curl https://dmlink.app/api/v1/links/abc123 \
-H "Authorization: Bearer $DMLINK_API_KEY"Resposta
{
"success": true,
"data": {
"campaignId": "cm1a2b3c4d5e6f",
"slug": "abc123",
"position": 1,
"label": "Primary campaign link",
"destinationUrl": "https://chat.whatsapp.com/CURRENT_GROUP",
"trackedUrl": "https://dmlink.app/r/abc123",
"updatedAt": "2026-10-02T12:00:00.000Z"
}
}6. Trocar o destino de um link
Corpo (JSON)
{ "destinationUrl": "https://chat.whatsapp.com/NEW_GROUP" }- O endereço tem que ser completo, começar com
https://e ter até 2048 caracteres. Links de convite do WhatsApp (https://chat.whatsapp.com/...) entram do jeito que vêm, inclusive com parâmetros depois do?. - A troca vale na hora: o
dmlink.app/r/{slug}já redireciona pro destino novo na chamada seguinte. - Mandar o mesmo destino de novo não dá erro: responde
"changed": falsee não muda nada, então pode repetir a chamada com segurança. Os endereços são comparados normalizados, entãohttps://site.comehttps://site.com/contam como o mesmo. - O endereço fica guardado na forma normalizada (ex.:
https://site.comvirahttps://site.com/). Isso não muda pra onde o link leva.
curl
curl -X PATCH https://dmlink.app/api/v1/links/abc123 \
-H "Authorization: Bearer $DMLINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"destinationUrl": "https://chat.whatsapp.com/NEW_GROUP"}'JavaScript (Node)
// Node 18+ (built-in fetch)
async function changeCampaignLink(slug, newUrl) {
const res = await fetch(`https://dmlink.app/api/v1/links/${slug}`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.DMLINK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ destinationUrl: newUrl }),
});
const json = await res.json();
if (!json.success) {
throw new Error(`DM Link refused (${res.status}): ${json.error.code} - ${json.error.message}`);
}
return json.data; // { changed, previousDestinationUrl, destinationUrl, ... }
}Python
import os
import requests
def change_campaign_link(slug: str, new_url: str) -> dict:
res = requests.patch(
f"https://dmlink.app/api/v1/links/{slug}",
headers={"Authorization": f"Bearer {os.environ['DMLINK_API_KEY']}"},
json={"destinationUrl": new_url},
timeout=15,
)
body = res.json()
if not body.get("success"):
raise RuntimeError(f"DM Link refused ({res.status_code}): {body['error']}")
return body["data"] # { changed, previousDestinationUrl, destinationUrl, ... }Resposta
{
"success": true,
"data": {
"campaignId": "cm1a2b3c4d5e6f",
"changed": true,
"previousDestinationUrl": "https://chat.whatsapp.com/CURRENT_GROUP",
"slug": "abc123",
"position": 1,
"label": "Primary campaign link",
"destinationUrl": "https://chat.whatsapp.com/NEW_GROUP",
"trackedUrl": "https://dmlink.app/r/abc123",
"updatedAt": "2026-10-02T12:05:00.000Z"
}
}Erros e limites
| Status | error.code | O que significa / o que fazer |
|---|---|---|
| 400 | invalid_json | O corpo não é JSON válido. Mande {"destinationUrl": "https://..."} com Content-Type: application/json. |
| 400 | invalid_destination | O endereço novo não é um https:// completo (ou passa de 2048 caracteres). |
| 401 | unauthorized | Chave ausente, errada ou desativada. Confira o cabeçalho Authorization: Bearer dml_.... |
| 403 | plan_required | A conta não está no plano Infinity. As chaves param enquanto ela estiver fora do Infinity e voltam a funcionar quando ela voltar. |
| 404 | not_found | Não existe link com esse slug (ou Instagram com esse ?instagram=) na conta da chave. Liste os Instagrams e as campanhas pra pegar o certo. |
| 429 | rate_limited | Passou de 60 chamadas por minuto com a mesma chave (o contador zera a cada minuto cheio do relógio). Espere e tente de novo. |
As mensagens de erro (error.message) vêm em inglês; pra decidir o que fazer no código, use o error.code, que é fixo. Se precisar listar campanhas com frequência, guarde o resultado em vez de consultar a cada vez.
Resumo das respostas
| Campo | O que é |
|---|---|
changed | true se o destino mudou; false se já era esse. |
previousDestinationUrl | Pra onde o link apontava antes desta chamada. |
destinationUrl | Pra onde o link aponta agora. |
trackedUrl | O link rastreado que vai nas mensagens (não muda nunca). |
instagram | Na lista de campanhas: id e username do Instagram dono da campanha. |
campaignId / position | A campanha dona do link e a posição dele nela: 1 = botão principal, 2 = segundo botão. A posição de um link não muda. |
Exemplo do fluxo completo
- Uma vez só, na configuração: chamar
GET /api/v1/instagram-accountse escolher o Instagram; depoisGET /api/v1/campaigns?instagram={username}, escolher a campanha pelonamee guardar oslugdo link (geralmente o deposition: 1). - O seu sistema acompanha o que decide o destino (ex.: quantas pessoas tem no grupo de WhatsApp atual).
- Na hora de trocar, ele chama
PATCH /api/v1/links/{slug}com o endereço novo. - Se a resposta vier
"success": true, pronto: o DM Link já está mandando todo mundo pro destino novo. Se der erro, tente de novo depois (a chamada é segura de repetir).
Cuidados
- A chave é como uma senha. Guarde numa variável de ambiente (ex.:
DMLINK_API_KEY), nunca no código nem no GitHub. Ela vale pra todas as campanhas de todos os Instagrams conectados na conta. - Vazou? Desative em Configurações → Chaves de API e crie outra. A antiga para na hora.
- Histórico: toda troca feita pela API fica registrada (quando, qual campanha, de qual endereço pra qual, por qual chave) em Configurações → Chaves de API.