API Keys
API keys let you access your DMARC Examiner data programmatically through the REST API. Use them to integrate DMARC monitoring into your own tools, dashboards, or automation workflows.
Creating an API Key
- Go to Settings > API Keys
- Click Create API Key
- Enter a descriptive name for the key (e.g., "Monitoring Dashboard", "CI Pipeline")
- Copy the key immediately — it will only be shown once
Each organization can have up to 5 active API keys. Keys are scoped to the organization and provide read access to all domains, reports, and alerts within it.
API Key Format
API keys follow the format dex_ followed by 32 hexadecimal characters:
dex_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6The dex_ prefix identifies the key as a DMARC Examiner API key. In the Settings UI, only the first 8 characters are displayed for identification.
Authentication
Include your API key in the X-API-Key header with every request:
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/domainsAvailable Endpoints
Dominios
Listar dominios
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/domainsRespuesta:
{
"data": [
{
"id": "uuid",
"name": "example.com",
"status": "active",
"verified_at": "2025-01-15T10:30:00Z",
"last_report_at": "2025-03-20T08:00:00Z",
"created_at": "2025-01-10T09:00:00Z"
}
]
}Crear un dominio
curl -X POST \
-H "X-API-Key: dex_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name":"example.com"}' \
https://api.dmarc-examiner.com/api/v1/domainsDevuelve 201 Created con el dominio creado. La respuesta incluye reporting_email y dmarc_record — cópialos en tu DNS para empezar a recibir reportes DMARC. Devuelve 409 Conflict si el dominio ya existe en la organización, o un error de límite de plan si superas el cupo.
Obtener un dominio
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/domains/{domain_id}Verificar un dominio
Re-consulta el DNS para localizar tu reporting email y actualiza el estado del dominio si lo encuentra.
curl -X POST \
-H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/domains/{domain_id}/verifyDevuelve 200 OK con {"verified": true, "domain": {...}} en caso de éxito, o 422 Unprocessable Entity con la razón si el DNS aún no contiene el reporting email.
Eliminar un dominio
curl -X DELETE \
-H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/domains/{domain_id}Devuelve 204 No Content en caso de éxito.
Comprobar registro DMARC existente (cualquier dominio)
Utilidad libre — no requiere que el dominio pertenezca a tu organización. Útil para due diligence antes de añadir un dominio nuevo.
curl -X POST \
-H "X-API-Key: dex_your_key_here" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}' \
https://api.dmarc-examiner.com/api/v1/check-dmarcDevuelve el registro DMARC existente (si lo hay), la política parseada y las direcciones de reporting.
Reports
List reports
curl -H "X-API-Key: dex_your_key_here" \
"https://api.dmarc-examiner.com/api/v1/reports?domain_id=uuid&page=1&limit=20"Query parameters:
| Parameter | Type | Description |
|---|---|---|
domain_id |
string | Filter by domain UUID |
date_from |
integer | Unix timestamp, filter reports starting from |
date_to |
integer | Unix timestamp, filter reports ending at |
page |
integer | Page number (default: 1) |
limit |
integer | Results per page (default: 20, max: 100) |
Get a single report
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/reports/{report_id}Returns the report with all individual records, including geolocation data.
Get report statistics
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/reports/{report_id}/statisticsReturns aggregated statistics grouped by country, ASN, and authentication result.
Export report as CSV
curl -H "X-API-Key: dex_your_key_here" \
-o report.csv \
https://api.dmarc-examiner.com/api/v1/reports/{report_id}/export/csvAlerts
List alerts
curl -H "X-API-Key: dex_your_key_here" \
"https://api.dmarc-examiner.com/api/v1/alerts?severity=critical&status=pending"Query parameters:
| Parameter | Type | Description |
|---|---|---|
severity |
string | Filter by severity: info, warning, critical |
status |
string | Filter by status: pending, sent, dismissed |
page |
integer | Page number (default: 1) |
limit |
integer | Results per page (default: 20, max: 100) |
Dismiss an alert
curl -X PUT \
-H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/alerts/{alert_id}/dismissReportes forenses (plan Pro o superior)
Los reportes forenses (DMARC RUF) contienen el detalle del mensaje fallido — IP del remitente, MAIL FROM original, resultados de autenticación por comprobación. Estos endpoints devuelven 403 Forbidden si el plan actual no incluye reportes forenses.
Listar reportes forenses
curl -H "X-API-Key: dex_your_key_here" \
"https://api.dmarc-examiner.com/api/v1/forensic-reports?domain_id=uuid&page=1&limit=20"Parámetros: domain_id, date_from, date_to, source_ip, auth_failure (dmarc / spf / dkim), page, limit.
Obtener un reporte forense
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/forensic-reports/{forensic_report_id}Devuelve el registro completo incluyendo resultados de autenticación parseados, geolocalización de la IP origen y las cabeceras originales (cuando estén disponibles).
Resumen (últimos 7 días)
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/forensic-reports/summaryEstadísticas agregadas
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/forensic-reports/statisticsWebhooks (plan Pro o superior)
Los webhooks permiten suscribirse a eventos y que los enviemos por POST a tu URL. Hoy el sistema emite un único evento:
alert.created— se dispara cada vez que se crea una alerta en tu organización (procesamiento de reportes o detección de cambios DNS).
Otros tipos (report.received, domain.verified) NO se emiten actualmente.
Estos endpoints devuelven 403 Forbidden si el plan no incluye alertas avanzadas. Las entregas fallidas se reintentan dos veces (30 s, 120 s) y el webhook se auto-deshabilita tras 10 fallos consecutivos.
Listar webhooks
curl -H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/webhooksCada webhook se crea con un secret que guardas en tu lado. Cada entrega va firmada con HMAC-SHA256 — el secret nunca viaja en la red.
Cómo se firma cada entrega
Cada POST a tu URL incluye:
| Header | Valor |
|---|---|
Content-Type |
application/json |
User-Agent |
DMARC-Examiner-Webhooks/1.0 |
X-Webhook-Timestamp |
Segundos Unix cuando firmamos el request |
X-Webhook-Signature |
sha256=<hex> — ver abajo |
Donde:
signed_value = "{X-Webhook-Timestamp}.{raw_request_body}"
signature = hex(HMAC-SHA256(secret, signed_value))
header = "sha256=" + signatureCómo verificar
- Rechaza requests donde
|now - X-Webhook-Timestamp| > 5 minutos. - Recalcula la firma esperada con tu secret guardado y el body crudo.
- Compara con igualdad en tiempo constante (nunca
==). - Solo entonces parsea el body.
Node.js
import crypto from 'node:crypto'
function verify(req, secret) {
const timestamp = req.headers['x-webhook-timestamp']
const sigHeader = req.headers['x-webhook-signature']
const rawBody = req.rawBody // string de bytes, NO JSON parseado
if (!timestamp || !sigHeader?.startsWith('sha256=')) return false
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex')
const got = sigHeader.slice('sha256='.length)
return crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(got, 'hex'))
}Python
import hmac, hashlib, time
def verify(headers, raw_body: bytes, secret: str) -> bool:
ts = headers.get('X-Webhook-Timestamp')
sig = headers.get('X-Webhook-Signature', '')
if not ts or not sig.startswith('sha256='):
return False
if abs(time.time() - int(ts)) > 300:
return False
signed = f"{ts}.{raw_body.decode()}".encode()
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig[len('sha256='):])PHP
function verify(array $headers, string $rawBody, string $secret): bool {
$ts = $headers['X-Webhook-Timestamp'] ?? null;
$sig = $headers['X-Webhook-Signature'] ?? '';
if (!$ts || !str_starts_with($sig, 'sha256=')) return false;
if (abs(time() - (int) $ts) > 300) return false;
$expected = hash_hmac('sha256', $ts . '.' . $rawBody, $secret);
return hash_equals($expected, substr($sig, strlen('sha256=')));
}Errores comunes
- Los frameworks parsean el JSON antes de tu handler, pero la firma es sobre los bytes crudos. Captura el body crudo antes del parseo (Express:
bodyParser.raw(), Symfony:$request->getContent(), Flask:request.get_data()). - Usar
==en lugar de comparación de tiempo constante es una vulnerabilidad timing-attack. - Saltarse la ventana de timestamp es una vulnerabilidad replay-attack.
Crear un webhook
curl -X POST \
-H "X-API-Key: dex_your_key_here" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/dmarc-events","name":"Producción"}' \
https://api.dmarc-examiner.com/api/v1/webhooksLa URL debe ser HTTPS. Cada organización tiene un máximo de webhooks activos.
Actualizar un webhook
curl -X PUT \
-H "X-API-Key: dex_your_key_here" \
-H "Content-Type: application/json" \
-d '{"is_active":false}' \
https://api.dmarc-examiner.com/api/v1/webhooks/{webhook_id}Acepta cualquier combinación de url, name, is_active.
Eliminar un webhook
curl -X DELETE \
-H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/webhooks/{webhook_id}Enviar evento de prueba
curl -X POST \
-H "X-API-Key: dex_your_key_here" \
https://api.dmarc-examiner.com/api/v1/webhooks/{webhook_id}/testDevuelve el resultado de la entrega (HTTP status, tiempo de respuesta, error si lo hay).
Rate Limits
API requests are limited to 100 requests per minute per API key. When the limit is exceeded, the API returns a 429 Too Many Requests response.
Revoking a Key
To revoke an API key:
- Go to Settings > API Keys
- Click the delete icon next to the key you want to revoke
- Confirm the revocation
Revoked keys stop working immediately and cannot be restored. You will need to create a new key and update your integrations.
Security Best Practices
- Never expose API keys in client-side code or public repositories
- Use environment variables to store keys in your applications
- Create separate keys for different integrations so you can revoke them independently
- Rotate keys periodically by creating a new key, updating your integration, and then revoking the old one