Programadores → Webhooks

Webhooks

A NameOcean envia um evento JSON assinado para o seu endpoint HTTPS quando algo acontece na sua conta, para que o seu código possa reagir em vez de consultar repetidamente.

Adicionar um endpoint

Em Painel → Webhooks, com a API ou pedindo à sua IA via MCP (create_webhook). Escolha tipos de evento, grupos como dns.* ou todos os eventos. A resposta inclui o segredo de assinatura (whsec_…).

curl
$ curl -X POST https://nameocean.net/api/v1/webhooks \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d '{"url": "https://example.com/hooks/nameocean", "events": ["dns.*", "ssl.issued", "domain.expiring"]}'

A URL deve ser HTTPS num servidor público. Responda com qualquer 2xx em até 10 segundos; faça o trabalho demorado depois de responder.

O que você recebe

POST https://example.com/hooks/nameocean
Content-Type: application/json
X-NameOcean-Event: dns.record.created
X-NameOcean-Delivery: whd_7c1e0f9a2b3d4e5f6a7b8c9d
X-NameOcean-Signature: t=1794300000,v1=5f2b…

{
  "id": "evt_3a9f1c2e4b5d6a7c8e9f0a1b",
  "type": "dns.record.created",
  "created": "2026-11-10T09:20:00+00:00",
  "data": {
    "zone": "example.com",
    "record": {"id": 4211, "type": "A", "hostname": "www", "ip": "203.0.113.10", "ttl": "1h"}
  }
}

O id do evento permanece o mesmo quando uma entrega é repetida ou reenviada: use-o para ignorar eventos que você já processou. Os eventos podem chegar fora de ordem.

Verifique a assinatura

t é o tempo Unix da requisição e v1 é o HMAC-SHA256 em hexadecimal de t, um ponto e o corpo bruto, usando o seu segredo como chave. Calcule-o sobre os bytes brutos, antes de analisar o JSON, compare em tempo constante e rejeite timestamps com mais de cinco minutos.

X-NameOcean-Signature
t=1794300000,v1=hex(HMAC_SHA256(secret, "1794300000." + raw_body))
Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    fields = dict(part.split("=", 1) for part in header.split(","))
    ts = int(fields["t"])
    if abs(time.time() - ts) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, fields.get("v1", ""))
Node.js
import crypto from "node:crypto";

export function verify(secret, header, rawBody, tolerance = 300) {
  const fields = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const ts = Number(fields.t);
  if (Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${ts}.`).update(rawBody).digest("hex");
  const got = Buffer.from(fields.v1 || "", "hex");
  return got.length === 32 && crypto.timingSafeEqual(Buffer.from(expected, "hex"), got);
}
Go
func Verify(secret, header string, body []byte) bool {
	var ts int64
	var v1 string
	for _, part := range strings.Split(header, ",") {
		k, v, _ := strings.Cut(part, "=")
		switch k {
		case "t":
			ts, _ = strconv.ParseInt(v, 10, 64)
		case "v1":
			v1 = v
		}
	}
	if d := time.Now().Unix() - ts; d > 300 || d < -300 {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	fmt.Fprintf(mac, "%d.", ts)
	mac.Write(body)
	return hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(v1))
}

Novas tentativas e desativação

Uma entrega sem resposta, com timeout, 5xx, 408 ou 429 é repetida após 1m, 5m, 30m, 2h, 5h, 10h, 10h: 8 tentativas ao longo de cerca de um dia. Qualquer outro 4xx falha imediatamente. Após 5 entregas seguidas falharem definitivamente, o endpoint é desativado e você recebe um email; reative-o no painel ou com PATCH active: true. Todas as entregas, com o código de status e o início da sua resposta, são listadas no painel e em GET /api/v1/webhooks/{id}/deliveries, onde você pode reenviar uma delas.

Eventos

domain.registeredUm domínio foi registrado na sua conta.
domain.renewedA data de expiração de um domínio foi adiada (renovação).
domain.expiringUm domínio expira em 30, 7 ou 1 dia.
domain.expiredUm domínio expirou ontem.
domain.nameservers.updatedOs nameservers de um domínio foram alterados.
domain.transfer.startedFoi solicitada no registro uma transferência de entrada ou de saída.
domain.transfer.completedUma transferência foi concluída.
domain.transfer.failedUma transferência foi rejeitada ou cancelada.
dns.zone.createdUma zona DNS foi criada.
dns.zone.deletedUma zona DNS foi excluída.
dns.record.createdUm registro DNS foi adicionado.
dns.record.updatedUm registro DNS foi alterado.
dns.record.deletedUm registro DNS foi excluído.
ssl.issuedUm certificado foi emitido pela primeira vez.
ssl.renewedUm certificado foi renovado.
ssl.expiringUm certificado expira em 7 dias e ainda não foi renovado.
email.mailbox.createdFoi adicionada uma caixa de correio a um dos seus domínios de e-mail.
email.mailbox.deletedUma caixa de correio e as respetivas mensagens foram eliminadas.
email.forwarding.enabledO reencaminhamento de e-mail foi ativado para um domínio.
email.forwarding.disabledO reencaminhamento de e-mail foi desativado para um domínio, por si ou porque o domínio deixou de cumprir os requisitos (o motivo consta do evento).
webhook.testEnviado quando você clica em Enviar teste; ignora o filtro de eventos do endpoint.

data contém o domínio ou a zona e o objeto: o registro (com previous nas atualizações), a data de expiração, os nameservers (com previous). Os campos exatos de cada objeto são os da API REST.

Emails recebidos também podem ser enviados para uma URL: configure-a por endereço em Encaminhamento de email. Esses envios usam os mesmos cabeçalhos e assinatura, com X-NameOcean-Event: email.received.

Bom saber

  • A NameOcean só envia para endereços públicos, verificados novamente a cada entrega, e nunca segue redirecionamentos.
  • Gere um novo segredo no painel caso ele vaze; os eventos passam a ser assinados com o novo imediatamente.
  • Enviar teste envia um evento webhook.test imediatamente, independentemente do filtro de eventos do endpoint.