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.

A API é do plano Infinity. As chaves só são criadas e só funcionam enquanto a conta está no Infinity: se a conta sair do Infinity, as chaves param de responder na hora, e voltam a funcionar quando ela voltar. Ver planos.

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:

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

  1. Entre no DM Link como dono ou administrador da conta.
  2. Vá em Configurações → Chaves de API.
  3. 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.
  4. 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

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/v1

Mande a chave em toda chamada

Authorization: Bearer dml_SUA_CHAVE

Também é aceito X-API-Key: dml_SUA_CHAVE. As respostas são sempre JSON: {"success": true, "data": ...} ou {"success": false, "error": {"code": "...", "message": "..."}}.

MétodoCaminhoPra que serve
GET/api/v1/instagram-accountsListar os Instagrams conectados na conta
GET/api/v1/campaignsListar as campanhas e os links de cada uma, de todos os Instagrams
GET/api/v1/campaigns?instagram=@usuarioListar 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

GEThttps://dmlink.app/api/v1/instagram-accounts

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
    }
  ]
}
CampoO que é
idIdentificador do Instagram no DM Link (não muda).
usernameO @ do Instagram, sem o @.
nameNome do perfil (pode vir null).
needsReconnecttrue 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.
campaignCountQuantas campanhas esse Instagram tem (ativas e pausadas).

4. Listar as campanhas de um Instagram

GEThttps://dmlink.app/api/v1/campaigns?instagram=@usuario

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.

Sobre os links de cada campanha:

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"
        }
      ]
    }
  ]
}
Dica: o slug não muda nunca, mesmo trocando o destino. Dá pra descobrir uma vez, guardar na configuração da sua integração e usar sempre.
GEThttps://dmlink.app/api/v1/links/{slug}
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

PATCHhttps://dmlink.app/api/v1/links/{slug}

Corpo (JSON)

{ "destinationUrl": "https://chat.whatsapp.com/NEW_GROUP" }

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

Statuserror.codeO que significa / o que fazer
400invalid_jsonO corpo não é JSON válido. Mande {"destinationUrl": "https://..."} com Content-Type: application/json.
400invalid_destinationO endereço novo não é um https:// completo (ou passa de 2048 caracteres).
401unauthorizedChave ausente, errada ou desativada. Confira o cabeçalho Authorization: Bearer dml_....
403plan_requiredA conta não está no plano Infinity. As chaves param enquanto ela estiver fora do Infinity e voltam a funcionar quando ela voltar.
404not_foundNã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.
429rate_limitedPassou 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

CampoO que é
changedtrue se o destino mudou; false se já era esse.
previousDestinationUrlPra onde o link apontava antes desta chamada.
destinationUrlPra onde o link aponta agora.
trackedUrlO link rastreado que vai nas mensagens (não muda nunca).
instagramNa lista de campanhas: id e username do Instagram dono da campanha.
campaignId / positionA 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

  1. Uma vez só, na configuração: chamar GET /api/v1/instagram-accounts e escolher o Instagram; depois GET /api/v1/campaigns?instagram={username}, escolher a campanha pelo name e guardar o slug do link (geralmente o de position: 1).
  2. O seu sistema acompanha o que decide o destino (ex.: quantas pessoas tem no grupo de WhatsApp atual).
  3. Na hora de trocar, ele chama PATCH /api/v1/links/{slug} com o endereço novo.
  4. 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