Anúncios · Delivery
A API de entrega permite que o site do cliente solicite anúncios para slots,
renderize-os e registre cliques. A impressão é contabilizada automaticamente no servidor durante a entrega; ao site cabe exibir o anúncio e, no clique, informar
o clickToken.
Fluxo de integração
- Entregar: peça um anúncio por formato (
GET …/formats/{format}) ou vários slots de uma vez (POST …/formats). A impressão é registrada no servidor neste passo. - Renderizar: se
filled === true, exibaimageUrl,title,content,linkTexte aponte o clique paralinkUrl. Guarde oclickToken. - Registrar clique: no clique do usuário, chame
POST …/tracking/clickcom oclickToken.
Entregar um anúncio (por formato)
Requer X-API-Key
Retorna um anúncio ativo e elegível para o formato, escolhido por prioridade
(maior primeiro; empates resolvidos aleatoriamente). Se não houver anúncio disponível,
retorna
filled: false.
Parâmetros de rota
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| format | AdFormat | Sim | Formato desejado: BANNER, SIDEBAR, POPUP, INLINE ou NATIVE. |
Exemplo de requisição
curl "https://api.draftin.io/public/ads/formats/BANNER" \
-H "X-API-Key: $DRAFTIN_API_KEY" const res = await fetch("https://api.draftin.io/public/ads/formats/BANNER", {
headers: { "X-API-Key": process.env.DRAFTIN_API_KEY },
});
const ad = await res.json();
if (ad.filled) {
// renderiza o anúncio e guarda ad.clickToken para o tracking de clique
} type AdFormat = "BANNER" | "SIDEBAR" | "POPUP" | "INLINE" | "NATIVE";
interface AdDeliveryResult {
filled: boolean;
id?: string;
imageUrl?: string | null;
linkUrl?: string | null;
title?: string | null;
content?: string | null;
linkText?: string | null;
clickToken?: string;
}
async function entregarAnuncio(format: AdFormat): Promise<AdDeliveryResult> {
const res = await fetch(`https://api.draftin.io/public/ads/formats/${format}`, {
headers: { "X-API-Key": process.env.DRAFTIN_API_KEY! },
});
if (!res.ok) throw new Error(`DraftIn Ads: ${res.status}`);
return res.json() as Promise<AdDeliveryResult>;
} Exemplo de resposta — preenchido
{
"filled": true,
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"imageUrl": "https://cdn.exemplo.com/ads/banner.jpg",
"linkUrl": "https://anunciante.exemplo.com/promo",
"title": "Conheça nosso produto",
"content": "A melhor solução para o seu time.",
"linkText": "Saiba mais",
"clickToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
} Exemplo de resposta — sem anúncio
{
"filled": false
} Campos do objeto AdDeliveryResult
true quando há anúncio para o formato; false quando nenhum está disponível (os demais campos vêm ausentes).POST /public/ads/tracking/click.Respostas possíveis
| Status | Significado |
|---|---|
| 200 OK | Resultado da entrega (filled: true com o anúncio, ou filled: false). |
| 400 Bad Request | Formato inválido (fora do enum AdFormat). |
| 401 Unauthorized | Chave de API ausente ou inválida. |
Entregar vários slots
Requer X-API-Key Content-Type: application/json
Solicita um anúncio para cada slot em uma única requisição, garantindo que não haja repetição de anúncios entre os slots. Os de maior prioridade são alocados primeiro; impressões são registradas no servidor para cada anúncio alocado.
Request body
Objeto AdDeliveryRequest com um array slots (de 1 a
20 itens):
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| slots | AdDeliverySlotRequest[] | Sim | Lista de slots a preencher. Mínimo 1, máximo 20 itens. |
| slots[].slotId | string | Sim | Identificador do slot definido por você (ex.: header-1). Volta na resposta para você casar resultado ↔ slot. |
| slots[].format | AdFormat | Sim | Formato desejado para o slot. |
Exemplo de requisição
curl -X POST "https://api.draftin.io/public/ads/formats" \
-H "X-API-Key: $DRAFTIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slots": [
{ "slotId": "header-1", "format": "BANNER" },
{ "slotId": "sidebar-1", "format": "SIDEBAR" }
]
}' const res = await fetch("https://api.draftin.io/public/ads/formats", {
method: "POST",
headers: {
"X-API-Key": process.env.DRAFTIN_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
slots: [
{ slotId: "header-1", format: "BANNER" },
{ slotId: "sidebar-1", format: "SIDEBAR" },
],
}),
});
const results = await res.json(); // um item por slot, na mesma ordem interface SlotRequest { slotId: string; format: AdFormat }
interface SlotResult extends AdDeliveryResult { slotId: string; format: AdFormat }
async function entregarSlots(slots: SlotRequest[]): Promise<SlotResult[]> {
const res = await fetch("https://api.draftin.io/public/ads/formats", {
method: "POST",
headers: {
"X-API-Key": process.env.DRAFTIN_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({ slots }),
});
if (!res.ok) throw new Error(`DraftIn Ads: ${res.status}`);
return res.json() as Promise<SlotResult[]>;
} Exemplo de resposta
Array com um AdDeliverySlotResult por slot, na mesma ordem da requisição. Cada item é um AdDeliveryResult acrescido de slotId e format:
[
{
"slotId": "header-1",
"format": "BANNER",
"filled": true,
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"imageUrl": "https://cdn.exemplo.com/ads/banner.jpg",
"linkUrl": "https://anunciante.exemplo.com/promo",
"title": "Conheça nosso produto",
"content": "A melhor solução para o seu time.",
"linkText": "Saiba mais",
"clickToken": "eyJhbGciOiJIUzI1NiI..."
},
{
"slotId": "sidebar-1",
"format": "SIDEBAR",
"filled": false
}
] Respostas possíveis
| Status | Significado |
|---|---|
| 200 OK | Array com um resultado por slot, na ordem da requisição. |
| 400 Bad Request | Body inválido: slots vazio, mais de 20 slots, ou slotId/format ausente. |
| 401 Unauthorized | Chave de API ausente ou inválida. |
Registrar clique
Requer X-API-Key Content-Type: application/json
Registra um clique no anúncio, identificado pelo clickToken recebido
na entrega. O endpoint aplica várias proteções anti-fraude — entendê-las evita
surpresas no código de status.
Request body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| clickToken | string | Sim | Token retornado pela entrega do anúncio (GET …/formats/{format} ou POST …/formats). |
Proteções anti-fraude
- Token obrigatório: use o
clickTokenda entrega. - Validação de origem: os headers
Origin/Refererdevem corresponder ao domínio configurado do blog (quando houver). Caso contrário,403. - Token assinado com TTL de 10 minutos (propósito
ad-click): expirado, retorna400. - Uso único: o mesmo token não pode ser reutilizado — reuso retorna
409. - Deduplicação por IP: cliques repetidos do mesmo IP no mesmo
anúncio em até 30 minutos são aceitos com
200, porém não incrementam a métrica (comportamento silencioso, para não revelar a lógica anti-fraude).
Exemplo de requisição
curl -X POST "https://api.draftin.io/public/ads/tracking/click" \
-H "X-API-Key: $DRAFTIN_API_KEY" \
-H "Content-Type: application/json" \
-H "Origin: https://seu-blog.com" \
-d '{ "clickToken": "eyJhbGciOiJIUzI1NiI..." }' // No clique do usuário, antes de seguir para o anúncio:
async function registrarClique(clickToken) {
await fetch("https://api.draftin.io/public/ads/tracking/click", {
method: "POST",
headers: {
"X-API-Key": DRAFTIN_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ clickToken }),
});
} async function registrarClique(clickToken: string): Promise<void> {
const res = await fetch("https://api.draftin.io/public/ads/tracking/click", {
method: "POST",
headers: {
"X-API-Key": process.env.DRAFTIN_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({ clickToken }),
});
// 200 = ok (mesmo quando deduplicado por IP). Não bloqueie a navegação por isto.
if (res.status === 409) console.warn("clickToken já utilizado");
if (res.status === 403) console.warn("origem não autorizada");
} Exemplo de resposta
{
"status": "ok"
} Respostas possíveis
| Status | Significado |
|---|---|
| 200 OK | Clique registrado (ou silenciosamente ignorado em caso de duplicidade por IP). |
| 400 Bad Request | clickToken ausente, inválido ou expirado. |
| 401 Unauthorized | Chave de API ausente ou inválida. |
| 403 Forbidden | Origem (Origin/Referer) não autorizada para este blog. |
| 409 Conflict | clickToken já utilizado. |
Registrar impressão no-op
Requer X-API-Key
Mantido apenas por compatibilidade com clientes existentes. As impressões já são contabilizadas automaticamente no servidor durante a entrega, então este endpoint sempre retorna sucesso sem efeito. Você não precisa chamá-lo em integrações novas.
Request body (opcional)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| clickToken | string | Não | Aceito por compatibilidade; ignorado pelo servidor. |
Respostas possíveis
| Status | Significado |
|---|---|
| 200 OK | Sempre { "status": "ok" } — nenhuma ação é executada. |
| 401 Unauthorized | Chave de API ausente ou inválida. |
Boas práticas
- Prefira a entrega em lote (
POST …/formats) quando a página tem múltiplos slots: menos requisições e sem anúncios repetidos. - Guarde o
clickTokenjunto do anúncio renderizado e use-o em até 10 minutos. - Garanta o
Origincorreto em chamadas server-side de clique, ou faça o clique a partir do domínio do blog. - Trate
filled: falseescondendo o slot ou exibindo um fallback — não renderize um anúncio vazio.