Sviluppatori → Webhooks

Webhook

NameOcean invia un evento JSON firmato al Suo endpoint HTTPS quando succede qualcosa nel Suo account, così il Suo codice può reagire senza dover interrogare periodicamente l'API.

Aggiungi un endpoint

In Dashboard → Webhook, tramite l'API oppure chiedendolo alla Sua AI tramite MCP (create_webhook). Scelga i tipi di evento, gruppi come dns.* o tutti gli eventi. La risposta include il secret di firma (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"]}'

L'URL deve essere https su un server pubblico. Risponda con un qualsiasi 2xx entro 10 secondi; esegua le operazioni lente dopo aver risposto.

Cosa riceve

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"}
  }
}

L'id dell'evento resta invariato quando una consegna viene ritentata o reinviata: lo usi per ignorare gli eventi già gestiti. Gli eventi possono arrivare in ordine diverso.

Verifichi la firma

t è il timestamp Unix della richiesta, v1 l'HMAC-SHA256 esadecimale di t, un punto e il corpo grezzo, firmato con il Suo segreto. Lo calcoli sui byte grezzi, prima di effettuare il parsing del JSON, esegua il confronto in tempo costante e rifiuti i timestamp più vecchi di cinque minuti.

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))
}

Nuovi tentativi e disattivazione

Una consegna che non riceve risposta, va in timeout o riceve un 5xx, 408 o 429 viene ritentata dopo 1m, 5m, 30m, 2h, 5h, 10h, 10h: 8 tentativi nell'arco di circa un giorno. Qualsiasi altro 4xx fallisce subito. Dopo 5 consegne consecutive fallite definitivamente, l'endpoint viene disattivato e riceve un'email; può riattivarlo dalla dashboard o con PATCH active: true. Ogni consegna, con il codice di stato e l'inizio della Sua risposta, è elencata nella dashboard e in GET /api/v1/webhooks/{id}/deliveries, dove può reinviarla.

Eventi

domain.registeredUn dominio è stato registrato nel Suo account.
domain.renewedLa data di scadenza di un dominio è stata posticipata (rinnovo).
domain.expiringUn dominio scade tra 30, 7 o 1 giorno.
domain.expiredUn dominio è scaduto ieri.
domain.nameservers.updatedI nameserver di un dominio sono cambiati.
domain.transfer.startedÈ stato richiesto un trasferimento in entrata o in uscita presso il registro.
domain.transfer.completedUn trasferimento è stato completato.
domain.transfer.failedUn trasferimento è stato rifiutato o annullato.
dns.zone.createdÈ stata creata una zona DNS.
dns.zone.deletedÈ stata eliminata una zona DNS.
dns.record.createdÈ stato aggiunto un record DNS.
dns.record.updatedUn record DNS è stato modificato.
dns.record.deletedÈ stato eliminato un record DNS.
ssl.issuedUn certificato è stato emesso per la prima volta.
ssl.renewedUn certificato è stato rinnovato.
ssl.expiringUn certificato scade tra 7 giorni e non è ancora stato rinnovato.
email.mailbox.createdÈ stata aggiunta una casella a uno dei Suoi domini di posta.
email.mailbox.deletedUna casella e i relativi messaggi sono stati eliminati.
email.forwarding.enabledL'inoltro email è stato attivato per un dominio.
email.forwarding.disabledL'inoltro email è stato disattivato per un dominio, da Lei o perché il dominio non soddisfa più i requisiti (il motivo è indicato nell'evento).
webhook.testInviato quando preme Invia test; ignora il filtro eventi dell'endpoint.

data contiene il dominio o la zona e l'oggetto: il record (con previous negli aggiornamenti), la data di scadenza, i nameserver (con previous). I campi esatti di ogni oggetto sono quelli della REST API.

Anche le email in arrivo possono essere inviate a un URL: lo imposti per ciascun indirizzo in Inoltro email. Questi invii usano gli stessi header e la stessa firma, con X-NameOcean-Event: email.received.

Buono a sapersi

  • NameOcean invia solo a indirizzi pubblici, verificati di nuovo a ogni consegna, e non segue mai i redirect.
  • Se il secret viene compromesso, lo rigeneri dalla dashboard; gli eventi vengono firmati subito con quello nuovo.
  • Invia test invia subito un evento webhook.test, indipendentemente dal filtro eventi dell'endpoint.