#pApiAuth
Referencia completa de campos de API & CLI: los 12 tipos de objeto, endpoints REST & POST /api/v1/send
Esta referencia documenta cada propiedad JSON, tipo de datos, valor enum, ajuste predeterminado y rol RBAC mínimo de los 12 objetos de gestión (/api/admin/cli/objects/{type} & nextxch-cli), así como la entrega de correo transaccional (POST /api/v1/send). Utilice el cuadro de filtro instantáneo situado sobre la tabla para buscar cualquier propiedad, como dkimSigningMode, tlsMode, allowedCidrs o warmingEnabled.
Introspección en vivo en su terminal o mediante HTTP: cada nextxch expone este esquema completo en JSON legible por máquina en GET /api/admin/cli/schema (con la cabecera SHA-256 X-Nextxch-Schema-Version). En su terminal, ejecute en cualquier momento nextxch-cli describe <Type> (p. ej., nextxch-cli describe Domain o nextxch-cli describe SmtpQueue).
TransactionalSendRequest (POST /api/v1/send)
13
IntegrationKey (API v1)
9
CalendarEvent (API v1)
12
Rooms & Booking (API v1)
6
Contact, Directory & Sharing (API v1)
9
Webhook (API v1)
4
Tenant
11
Domain
19
Account (Account/User & Account/List)
18
Alias
7
ApiKey
11
Route
10
TransactionalSend (Singleton)
11
ReputationShield (Singleton)
20
SpamGuard (Singleton)
15
SmtpQueue (Singleton)
19
TransportRules & Server (Singletons)
11
TransactionalSendRequest (POST /api/v1/send)
Clave: Idempotency-Key
RBAC: User+
Endpoint HTTP JSON de alto rendimiento para la entrega desde aplicaciones web, ERP, CRM y códigos 2FA, con priorización por categorías, calentamiento de IP, comprobación previa de supresión e idempotencia de 24 h.
/api/v1/send
Pone en cola y firma el correo transaccional (UTF-8 Multipart/Alternative + archivos adjuntos)
/api/v1/unsubscribe/{token}
Endpoint público de baja con un clic según RFC 8058 (token firmado con DKIM)
from
string
OPCIONAL
Key senderAddress
to
string[]
OBLIGATORIO
cc
string[]
OPCIONAL
[]
bcc
string[]
OPCIONAL
[]
replyTo
string
OPCIONAL
subject
string
OBLIGATORIO
textBody
string
OPCIONAL
htmlBody
string
OPCIONAL
category
string
OPCIONAL
transactional
"critical""transactional""notification""marketing"overflowMode
string
OPCIONAL
DeferQueue
"DeferQueue""Reject429"idempotencyKey
string
OPCIONAL
Header Idempotency-Key
headers
Record<string, string>
OPCIONAL
{}
attachments
SendAttachmentDto[]
OPCIONAL
[]
{
"from": "Abrechnung <rechnung@firma.de>",
"to": ["einkauf@kunde.de"],
"cc": ["buchhaltung@firma.de"],
"subject": "Ihre elektronische Rechnung RE-2026-90412",
"category": "transactional",
"overflowMode": "DeferQueue",
"textBody": "Guten Tag,\nanbei erhalten Sie Ihre Rechnung RE-2026-90412.",
"htmlBody": "<p>Guten Tag,</p><p>anbei erhalten Sie Ihre Rechnung <strong>RE-2026-90412</strong>.</p>",
"headers": {
"X-ERP-Document-Id": "RE-2026-90412"
},
"attachments": [
{
"fileName": "RE-2026-90412.pdf",
"contentType": "application/pdf",
"base64Content": "JVBERi0xLjcKJcfs..."
}
]
}
# 1) Kleinstprivilegierten Sende-Key (Role=User) für rechnung@firma.de erstellen:
nextxch-cli create ApiKey \
--set label="ERP Rechnungsversand" \
--set role=User \
--set senderAddress=rechnung@firma.de \
--set defaultCategory=transactional \
--set allowedCidrs=10.20.0.0/16
# 2) Risikofreier Trockentest gegen die integrierte Sandbox-Sink-Domain:
# ok@sink.nextxch.local | bounce@sink.nextxch.local | defer@sink.nextxch.local
curl -fsS -X POST "https://mail.firma.de/api/v1/send" \
-H "Authorization: Bearer smk_01968f2a_..." \
-H "Idempotency-Key: inv-2026-90412" \
-H "Content-Type: application/json" \
-d '{
"from": "rechnung@firma.de",
"to": ["einkauf@kunde.de"],
"subject": "Ihre Rechnung RE-2026-90412",
"category": "transactional",
"textBody": "Guten Tag, anbei Ihre Rechnung RE-2026-90412.",
"htmlBody": "<p>Guten Tag, anbei Ihre Rechnung <b>RE-2026-90412</b>.</p>"
}'
using System.Net.Http.Headers;
using System.Net.Http.Json;
using var http = new HttpClient { BaseAddress = new Uri("https://mail.firma.de") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "smk_01968f2a_...");
http.DefaultRequestHeaders.Add("Idempotency-Key", "inv-2026-90412");
var response = await http.PostAsJsonAsync("/api/v1/send", new
{
from = "rechnung@firma.de",
to = new[] { "einkauf@kunde.de" },
subject = "Ihre Rechnung RE-2026-90412",
category = "transactional",
textBody = "Guten Tag, anbei Ihre Rechnung RE-2026-90412.",
htmlBody = "<p>Guten Tag, anbei Ihre Rechnung <strong>RE-2026-90412</strong>.</p>"
});
response.EnsureSuccessStatusCode();
IntegrationKey (API v1)
Clave: id
RBAC: TenantAdmin+
Clave de integración con ámbitos para /api/v1. Una clave actúa en nombre de un usuario o, como integración de inquilino, en nombre del usuario indicado en el encabezado X-Nextxch-Act-As. Sin el ámbito, la API responde 403; un usuario de otro inquilino da 404. Credenciales de cliente OAuth 2.0 opcionales (token válido durante 1 hora).
/api/admin/integrations/keys
Crear una clave (admin, se muestra una vez)
/api/admin/integrations/keys/{id}
Cambiar ámbitos
/api/admin/integrations/keys/{id}
Revocar una clave (y sus tokens OAuth)
/api/v1/oauth/token
OAuth 2.0 client_credentials: ID de clave + clave para obtener un token de acceso
/api/v1/me
Clave, ámbitos y usuario que actúa
/api/v1/openapi.json
Documento OpenAPI 3.1 de la instalación
label
string
OBLIGATORIO
mode
string
OBLIGATORIO
user
"user""tenant"userEmail
string
OPCIONAL
scopes
string[]
OBLIGATORIO
"calendar.read""calendar.write""rooms.read""booking.read""booking.write""contacts.read""contacts.write""directory.read""sharing.manage""webhooks.manage""mail.send"domainId
guid
OPCIONAL
allowedCidrs
string[]
OPCIONAL
[]
expiresInDays
integer
OPCIONAL
senderAddress
string
OPCIONAL
apiKey
string
SOLO LECTURA
{
"label": "CRM",
"mode": "tenant",
"scopes": ["calendar.write", "rooms.read", "contacts.write", "webhooks.manage"],
"allowedCidrs": ["203.0.113.0/24"],
"expiresInDays": 365
}
# Integrations-Schlüssel: Admin > API & Integrationen > Neuer Schlüssel
# Danach z. B. ein Access-Token per OAuth 2.0 Client Credentials holen:
curl -fsS -X POST "https://mail.firma.de/api/v1/oauth/token" \
-d grant_type=client_credentials \
-d client_id=0196c3a2-5f1e-7c11-9a20-1c2d3e4f5a6b \
-d client_secret=smk_0196c3a25f1e7c119a201c2d3e4f5a6b_... \
-d scope="calendar.read rooms.read"
curl -fsS "https://mail.firma.de/api/v1/me" \
-H "Authorization: Bearer smk_0196c3a2..." \
-H "X-Nextxch-Act-As: anna@firma.de"
using var http = new HttpClient { BaseAddress = new Uri("https://mail.firma.de") };
http.DefaultRequestHeaders.Authorization = new("Bearer", "smk_0196c3a2...");
http.DefaultRequestHeaders.Add("X-Nextxch-Act-As", "anna@firma.de");
var me = await http.GetFromJsonAsync<JsonElement>("/api/v1/me");
CalendarEvent (API v1)
Clave: hrefName
RBAC: User+
Eventos con series y excepciones, asistentes, salas, invitaciones, respuestas, disponible/ocupado, calendarios compartidos y globales y enlaces de invitación. Ámbitos calendar.read y calendar.write. Horas en UTC (ISO-8601), zonas horarias como nombres IANA.
/api/v1/calendars
Calendarios propios, compartidos, globales y de recursos
/api/v1/calendar/events?from&to&calendarId&limit&cursor
Repeticiones en un intervalo (serie expandida)
/api/v1/calendar/events
Crear un evento (invitar a personas y salas)
/api/v1/calendar/events/{hrefName}
Evento con series y excepciones
/api/v1/calendar/events/{hrefName}
Modificación; scope=occurrence|following para partes de una serie
/api/v1/calendar/events/{hrefName}
Eliminar, opcionalmente con cancelaciones (notify=true)
/api/v1/calendar/events/{hrefName}/respond
Responder a una invitación
/api/v1/calendar/events/{hrefName}/invite-link
Enlace de invitación firmado
/api/v1/calendar/events/{hrefName}/ics
iCalendar sin procesar
/api/v1/calendar/freebusy
Disponible/ocupado de personas y salas
title
string
OBLIGATORIO
startUtc
datetime
OBLIGATORIO
endUtc
datetime
OBLIGATORIO
timeZone
string
OPCIONAL
Europe/Berlin
allDay
boolean
OPCIONAL
false
attendees
Attendee[]
OPCIONAL
[]
sendInvitations
boolean
OPCIONAL
false
recurrence
Recurrencia
OPCIONAL
showAs
string
OPCIONAL
busy
"free""tentative""busy""oof""workingElsewhere"isPrivate
boolean
OPCIONAL
false
calendarId
string
OPCIONAL
teamsMeeting
boolean
OPCIONAL
{
"title": "Projektstart",
"startUtc": "2026-12-03T09:00:00Z",
"endUtc": "2026-12-03T10:00:00Z",
"timeZone": "Europe/Berlin",
"attendees": [
{ "email": "bernd@firma.de" },
{ "email": "raum-1@firma.de" }
],
"sendInvitations": true
}
# Benötigte Scopes: calendar.read (lesen), calendar.write (schreiben)
# Einen Raum buchen: Raumadresse als Teilnehmer eintragen
curl -fsS -X POST "https://mail.firma.de/api/v1/calendar/events" \
-H "Authorization: Bearer smk_0196c3a2..." \
-H "X-Nextxch-Act-As: anna@firma.de" \
-H "Content-Type: application/json" \
-d '{"title":"Projektstart","startUtc":"2026-12-03T09:00:00Z","endUtc":"2026-12-03T10:00:00Z","timeZone":"Europe/Berlin","attendees":[{"email":"raum-1@firma.de"}]}'
var res = await http.PostAsJsonAsync("/api/v1/calendar/events", new
{
title = "Projektstart",
startUtc = DateTimeOffset.Parse("2026-12-03T09:00:00Z"),
endUtc = DateTimeOffset.Parse("2026-12-03T10:00:00Z"),
timeZone = "Europe/Berlin",
attendees = new[] { new { email = "raum-1@firma.de" } }
});
string href = (await res.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("data").GetProperty("hrefName").GetString()!;
Rooms & Booking (API v1)
Clave: id
RBAC: User+
Salas y recursos con disponibilidad (rooms.read) y páginas de reservas al estilo de Calendly (booking.read, booking.write): página de reservas, tipos de eventos, franjas libres, lectura y cancelación de reservas. Una sala se reserva mediante un evento con la sala como asistente.
/api/v1/rooms?startUtc&endUtc&category
Salas y recursos, con disponibilidad para el intervalo
/api/v1/rooms/{email}/availability
Horas ocupadas de una sala
/api/v1/booking/profile
Página de reservas con horarios y tipos de evento
/api/v1/booking/event-types
Tipos de eventos
/api/v1/booking/event-types
Crear un tipo de evento
/api/v1/booking/event-types/{id}/slots?from&to
Horarios de inicio libres (máx. 42 días)
/api/v1/booking/bookings?status&from&to
Reservas
/api/v1/booking/bookings/{id}/cancel
Cancelar una reserva (se informa al invitado)
slots[].startUtc
datetime
SOLO LECTURA
slots[].endUtc
datetime
SOLO LECTURA
slots[].staff
object[]
SOLO LECTURA
status
string
SOLO LECTURA
"confirmed""cancelled"guest
object
SOLO LECTURA
free
boolean
SOLO LECTURA
{
"ok": true,
"data": {
"eventTypeId": "beratung-3f2a",
"durationMinutes": 30,
"timeZone": "Europe/Berlin",
"slots": [
{ "startUtc": "2026-12-04T08:00:00Z", "endUtc": "2026-12-04T08:30:00Z", "staff": [] }
]
}
}
# Benötigte Scopes: rooms.read, booking.read, booking.write
curl -fsS "https://mail.firma.de/api/v1/rooms?startUtc=2026-12-03T09:00:00Z&endUtc=2026-12-03T10:00:00Z" \
-H "Authorization: Bearer smk_0196c3a2..."
var slots = await http.GetFromJsonAsync<JsonElement>("/api/v1/booking/event-types/beratung/slots");
foreach (var s in slots.GetProperty("data").GetProperty("slots").EnumerateArray())
Console.WriteLine(s.GetProperty("startUtc").GetString());
Contact, Directory & Sharing (API v1)
Clave: hrefName
RBAC: User+
Contactos personales con todos los campos y foto (contacts.read, contacts.write, If-Match para la protección frente a conflictos), lista global de direcciones (directory.read) y usos compartidos y delegación (sharing.manage, delegación = permiso de buzón con sendAs o sendOnBehalf).
/api/v1/contacts?q
Buscar contactos
/api/v1/contacts
Crear un contacto
/api/v1/contacts/{hrefName}
Modificar un contacto (los campos null se mantienen)
/api/v1/contacts/{hrefName}
Eliminar un contacto
/api/v1/directory?q&type
Lista global de direcciones
/api/v1/sharing/grants
Permisos propios
/api/v1/sharing/grants
Establecer o quitar una concesión
/api/v1/sharing/shared-with-me
Compartido conmigo
givenName
string
OPCIONAL
familyName
string
OPCIONAL
organization
string
OPCIONAL
emails
TypedValue[]
OPCIONAL
[]
phones
TypedValue[]
OPCIONAL
[]
addresses
Address[]
OPCIONAL
[]
birthday
string
OPCIONAL
photo
string
SOLO ESCRITURA (SECRETO)
permissions
string[]
OPCIONAL
"freeBusy""read""write""delete""sendOnBehalf""sendAs""manage"{
"givenName": "Clara",
"familyName": "Kunde",
"organization": "Kunde AG",
"emails": [{ "type": "work", "value": "clara@kunde.example" }],
"phones": [{ "type": "cell", "value": "+49 170 1234567" }]
}
# Benötigte Scopes: contacts.read, contacts.write, directory.read, sharing.manage
curl -fsS -X POST "https://mail.firma.de/api/v1/contacts" \
-H "Authorization: Bearer smk_0196c3a2..." \
-H "Content-Type: application/json" \
-d '{"givenName":"Clara","familyName":"Kunde","emails":[{"type":"work","value":"clara@kunde.example"}]}'
await http.PutAsJsonAsync("/api/v1/sharing/grants", new
{
kind = "calendar", granteeType = "user", grantee = "bernd@firma.de", permissions = new[] { "read" }
});
Webhook (API v1)
Clave: id
RBAC: User+
Eventos como POST JSON firmado: calendar.event.created, calendar.event.updated, calendar.event.deleted, calendar.invitation.replied, booking.created, booking.rescheduled, booking.cancelled. Firma X-Nextxch-Signature: v1=hex(HMAC-SHA256(secret, X-Nextxch-Timestamp + "." + body)). Reintentos tras 30 s, 2 min, 10 min, 1 h y 6 h.
/api/v1/webhooks
Webhooks del inquilino
/api/v1/webhooks
Registrar un webhook (secreto solo en la respuesta)
/api/v1/webhooks/{id}
Eliminar un webhook
/api/v1/webhooks/{id}/deliveries
Entregas recientes
/api/v1/webhooks/{id}/test
Enviar un evento de prueba
url
string
OBLIGATORIO
events
string[]
OBLIGATORIO
"calendar.event.created""calendar.event.updated""calendar.event.deleted""calendar.invitation.replied""booking.created""booking.rescheduled""booking.cancelled""*"secret
string
SOLO LECTURA
id (Ereignis)
string
SOLO LECTURA
{
"id": "evt_5c1f0e9a2b7d4c3e8f601a2b",
"type": "calendar.invitation.replied",
"createdAtUtc": "2026-12-01T10:15:02Z",
"tenantId": "0196c3a2-0000-7000-8000-000000000001",
"data": {
"calendarId": "0196c3a25f1e7c11:default",
"hrefName": "0196c3a2@nextxch.ics",
"title": "Projektstart",
"startUtc": "2026-12-03T09:00:00Z",
"attendee": { "email": "bernd@firma.de", "partStat": "ACCEPTED" }
}
}
# Signatur prüfen (Bash):
# expected="v1=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)"
curl -fsS -X POST "https://mail.firma.de/api/v1/webhooks" \
-H "Authorization: Bearer smk_0196c3a2..." \
-H "Content-Type: application/json" \
-d '{"url":"https://crm.firma.de/hooks/nextxch","events":["calendar.event.created","booking.created"]}'
// ASP.NET Core receiver
app.MapPost("/hooks/nextxch", async (HttpRequest req) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
string ts = req.Headers["X-Nextxch-Timestamp"]!;
byte[] mac = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), [.. Encoding.ASCII.GetBytes(ts + "."), .. ms.ToArray()]);
return req.Headers["X-Nextxch-Signature"] == "v1=" + Convert.ToHexStringLower(mac) ? Results.Ok() : Results.Unauthorized();
});
Tenant
Clave: slug
RBAC: ServerAdmin+
Límite organizativo multiinquilino que aísla dominios, entidades de seguridad, cuotas de almacenamiento (GiB) y la retención de cumplimiento GoBD WORM predeterminada.
/api/admin/cli/objects/Tenant
Enumera todos los inquilinos
/api/admin/cli/objects/Tenant/{slugOrId}
Obtiene el inquilino por slug o UUID
/api/admin/cli/objects/Tenant
Crea un nuevo inquilino
/api/admin/cli/objects/Tenant/{slugOrId}
Actualiza las cuotas del inquilino en el momento
id
guid
SOLO LECTURA
UUIDv7
slug
string
PRIMARY KEY
name
string
OBLIGATORIO
isActive
boolean
OPCIONAL
true
maxDomains
integer
OPCIONAL
100
maxPrincipals
integer
OPCIONAL
10000
quotaGb
integer
OPCIONAL
100
outboundDailyLimit
integer
OPCIONAL
25000
defaultLockMode
string
OPCIONAL
Normal
"Normal""Governance""Compliance""LegalHold"defaultRetentionDays
integer
OPCIONAL
0
createdAtUtc
datetime
SOLO LECTURA
{
"slug": "acme",
"name": "ACME Logistik GmbH",
"isActive": true,
"maxDomains": 50,
"maxPrincipals": 2500,
"quotaGb": 250,
"outboundDailyLimit": 25000,
"defaultLockMode": "Compliance",
"defaultRetentionDays": 3650
}
# Mandant anlegen:
nextxch-cli create Tenant \
--set slug=acme \
--set name="ACME Logistik GmbH" \
--set quotaGb=250 \
--set defaultLockMode=Compliance \
--set defaultRetentionDays=3650
# Mandant abfragen & Kontingent erhöhen:
nextxch-cli get Tenant acme
nextxch-cli update Tenant acme --set quotaGb=500
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Tenant" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"slug":"acme","name":"ACME Logistik GmbH","quotaGb":250,"defaultLockMode":"Compliance","defaultRetentionDays":3650}'
var payload = new
{
slug = "acme",
name = "ACME Logistik GmbH",
quotaGb = 250,
defaultLockMode = "Compliance",
defaultRetentionDays = 3650
};
using var res = await http.PostAsJsonAsync("/api/admin/cli/objects/Tenant", payload);
Domain
Clave: name
RBAC: TenantAdmin+
Dominio de correo alojado con generación automática y paralela de claves Dual-DKIM (RSA-2048 + Ed25519), política de retención GoBD WORM, direcciones con sufijo (plus addressing) y límites de tasa.
/api/admin/cli/objects/Domain
Enumera todos los dominios
/api/admin/cli/objects/Domain/{name}
Obtiene la configuración del dominio & los selectores DKIM
/api/admin/cli/objects/Domain
Crea el dominio & genera claves DKIM RSA-2048 + Ed25519
/api/admin/cli/objects/Domain/{name}
Actualiza el modo DKIM, las cuotas o la retención en 0 ms
/api/admin/cli/dns/{name}?live=true
Verifica registros DNS en vivo o exporta una zona BIND según RFC 1035
id
guid
SOLO LECTURA
UUIDv7
name
string
PRIMARY KEY
tenant
string
OPCIONAL
default
isActive
boolean
OPCIONAL
true
postmasterAddress
string
OPCIONAL
postmaster@<name>
dkimSigningMode
string
OPCIONAL
Dual
"Rsa2048""Ed25519""Dual"dkimRsaSelector
string
OPCIONAL
s2026
dkimRsaDnsName
string
SOLO LECTURA
s2026._domainkey.<name>
dkimEd25519Selector
string
OPCIONAL
ed2026
dkimEd25519DnsName
string
SOLO LECTURA
ed2026._domainkey.<name>
retentionLockMode
string
OPCIONAL
Normal
"Normal""Governance""Compliance""LegalHold"retentionDays
integer
OPCIONAL
0
quotaGb
integer
OPCIONAL
50
maxMessageSizeMb
integer
OPCIONAL
50
maxAccounts
integer
OPCIONAL
1000
outboundDailyLimit
integer
OPCIONAL
5000
outboundHourlyLimit
integer
OPCIONAL
1000
usePlusAddressing
boolean
OPCIONAL
true
createdAtUtc
datetime
SOLO LECTURA
{
"name": "muster-logistik.de",
"tenant": "default",
"isActive": true,
"postmasterAddress": "postmaster@muster-logistik.de",
"dkimSigningMode": "Dual",
"dkimRsaSelector": "s2026",
"dkimEd25519Selector": "ed2026",
"retentionLockMode": "Compliance",
"retentionDays": 3650,
"quotaGb": 100,
"maxMessageSizeMb": 50,
"maxAccounts": 500,
"outboundDailyLimit": 10000,
"outboundHourlyLimit": 2000,
"usePlusAddressing": true
}
# Domain mit Dual-DKIM und 10 Jahren GoBD-Compliance anlegen:
nextxch-cli create Domain \
--set name=muster-logistik.de \
--set dkimSigningMode=Dual \
--set retentionLockMode=Compliance \
--set retentionDays=3650
# Fertige RFC-1035 BIND-Zonendatei exportieren & DNS live prüfen:
nextxch-cli dns muster-logistik.de --bind > muster-logistik.de.zone
nextxch-cli dns muster-logistik.de --live
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/Domain/muster-logistik.de" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"dkimSigningMode":"Dual","retentionLockMode":"Compliance","retentionDays":3650}'
using var res = await http.PatchAsJsonAsync(
"/api/admin/cli/objects/Domain/muster-logistik.de",
new { dkimSigningMode = "Dual", quotaGb = 200 });
res.EnsureSuccessStatusCode();
Account (Account/User & Account/List)
Clave: email
RBAC: TenantAdmin+
Representa un buzón de usuario (@type="User", con IMAP/JMAP/CalDAV/CardDAV/ActiveSync) o una lista de distribución (@type="List" con members[]).
/api/admin/cli/objects/Account?filter=role=TenantAdmin
Enumera/filtra cuentas y listas de distribución
/api/admin/cli/objects/Account/User
Crea un nuevo buzón de usuario con carpetas según RFC 6154
/api/admin/cli/objects/Account/List
Crea una nueva lista de distribución
/api/admin/cli/objects/Account/{email}
Actualiza cuota, reenvío, respuesta automática o contraseña
/api/admin/cli/objects/Account/{email}
Elimina una cuenta de forma lógica (soft delete)
id
guid
SOLO LECTURA
UUIDv7
@type
string
OPCIONAL
User
"User""List"email
string
PRIMARY KEY
displayName
string
OPCIONAL
Lokalteil
password
string
SOLO ESCRITURA (SECRETO)
role
string
OPCIONAL
User
"User""ComplianceAuditor""TenantAdmin""ServerAdmin"isActive
boolean
OPCIONAL
true
quotaMb
integer
OPCIONAL
5120
usedBytes
long
SOLO LECTURA
0
outboundDailyLimit
integer
OPCIONAL
500
forwardAddress
string
OPCIONAL
forwardKeepOriginal
boolean
OPCIONAL
true
vacationEnabled
boolean
OPCIONAL
false
vacationSubject
string
OPCIONAL
vacationBody
string
SOLO ESCRITURA (SECRETO)
twoFactorEnabled
boolean
SOLO LECTURA
false
members
string[]
OPCIONAL
[]
createdAtUtc
datetime
SOLO LECTURA
{
"@type": "User",
"email": "anna.weber@muster-logistik.de",
"displayName": "Anna Weber (IT-Leitung)",
"password": "SicheresStartPasswort!2026",
"role": "TenantAdmin",
"isActive": true,
"quotaMb": 15360,
"outboundDailyLimit": 1000,
"forwardAddress": null,
"forwardKeepOriginal": true,
"vacationEnabled": false,
"vacationSubject": "Abwesenheitsnotiz: Anna Weber",
"vacationBody": "Ich bin ab Montag wieder erreichbar."
}
# Benutzerpostfach (15 GiB Quota) anlegen:
nextxch-cli create Account/User \
--set email=anna.weber@muster-logistik.de \
--set displayName="Anna Weber" \
--set password="SicheresStartPasswort!2026" \
--set quotaMb=15360
# Verteilerliste anlegen:
nextxch-cli create Account/List \
--set email=team@muster-logistik.de \
--set displayName="Disposition & Einkauf" \
--set members=anna.weber@muster-logistik.de,dispo@muster-logistik.de
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Account/User" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"email":"anna.weber@muster-logistik.de","displayName":"Anna Weber","password":"SicheresStartPasswort!2026","quotaMb":15360}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Account/User", new
{
email = "anna.weber@muster-logistik.de",
displayName = "Anna Weber",
password = "SicheresStartPasswort!2026",
quotaMb = 15360
});
Alias
Clave: address
RBAC: TenantAdmin+
Alias de correo secundario o alias de privacidad enmascarado desechable, dirigido a un buzón Account principal o a una lista de distribución.
/api/admin/cli/objects/Alias
Enumera todos los alias y correos enmascarados
/api/admin/cli/objects/Alias
Crea un nuevo alias dirigido a un buzón de destino
/api/admin/cli/objects/Alias/{address}
Activa/pausa un alias o actualiza su destino
/api/admin/cli/objects/Alias/{address}
Elimina el alias
address
string
PRIMARY KEY
target
string
OBLIGATORIO
principalId
guid
SOLO LECTURA
description
string
OPCIONAL
""
isMasked
boolean
OPCIONAL
false
isEnabled
boolean
OPCIONAL
true
createdAtUtc
datetime
SOLO LECTURA
{
"address": "shop-8f2k@muster-logistik.de",
"target": "anna.weber@muster-logistik.de",
"description": "Fachbuchhandlung / Online-Bestellung",
"isMasked": true,
"isEnabled": true
}
# Masked-Email-Alias anlegen:
nextxch-cli create Alias \
--set address=shop-8f2k@muster-logistik.de \
--set target=anna.weber@muster-logistik.de \
--set description="Fachbuchhandlung" \
--set isMasked=true
# Alias bei Spam-Aufkommen mit 1 Befehl stummschalten:
nextxch-cli update Alias shop-8f2k@muster-logistik.de --set isEnabled=false
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Alias" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"address":"vertrieb@muster-logistik.de","target":"anna.weber@muster-logistik.de","description":"Vertrieb & Angebote"}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Alias", new
{
address = "vertrieb@muster-logistik.de",
target = "anna.weber@muster-logistik.de",
description = "Vertrieb & Angebote",
isEnabled = true
});
ApiKey
Clave: id
RBAC: TenantAdmin+
Clave de API con ámbito (Scoped API Key), inmutable y restringida por RBAC y CIDR (smk_<id>_<secret>) para /api/v1/send, SCIM 2.0 o nextxch-cli.
/api/admin/cli/objects/ApiKey
Enumera las claves de API activas (sin el secreto)
/api/admin/cli/objects/ApiKey
Emite una nueva clave de API y devuelve apiKey (smk_...) una sola vez
/api/admin/cli/objects/ApiKey/{id}
Revoca la clave de API de inmediato
id
guid
SOLO LECTURA
UUIDv7
apiKey
string
SOLO CREACIÓN
smk_<id>_<secret>
label
string
OBLIGATORIO
role
string
OPCIONAL
TenantAdmin
"User""ComplianceAuditor""TenantAdmin""ServerAdmin"senderAddress
string
OPCIONAL
defaultCategory
string
OPCIONAL
transactional
"critical""transactional""notification""marketing"allowedCidrs
string[]
OPCIONAL
[] (Alle IPs)
expiresInDays
integer
SOLO ESCRITURA (SECRETO)
null (Kein Ablauf)
expiresAtUtc
datetime
SOLO LECTURA
outboundDailyLimit
integer
OPCIONAL
10000
isActive
boolean
SOLO LECTURA
true
{
"label": "Shopware 6 ERP Rechnungsversand",
"role": "User",
"senderAddress": "rechnung@muster-logistik.de",
"defaultCategory": "transactional",
"allowedCidrs": ["10.20.10.15/32", "2a01:4f8:120:44aa::/64"],
"expiresInDays": 180,
"outboundDailyLimit": 10000
}
# CIDR-geschützten Key für Ansible / nextxch-cli erstellen:
nextxch-cli create ApiKey \
--set label="GitLab CI / Ansible" \
--set role=TenantAdmin \
--set allowedCidrs=10.20.0.0/16 \
--set expiresInDays=90
# Schlüssel widerrufen:
nextxch-cli delete ApiKey 0195f2a0-8b14-7000-9a10-001122334455
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/ApiKey" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"label":"Shopware 6","role":"User","senderAddress":"rechnung@muster-logistik.de","allowedCidrs":["10.20.10.15/32"],"expiresInDays":180}'
var res = await http.PostAsJsonAsync("/api/admin/cli/objects/ApiKey", new
{
label = "Shopware 6",
role = "User",
senderAddress = "rechnung@muster-logistik.de",
allowedCidrs = new[] { "10.20.10.15/32" },
expiresInDays = 180
});
var created = await res.Content.ReadFromJsonAsync<JsonElement>();
string oneTimeSecretKey = created.GetProperty("apiKey").GetString()!;
Route
Clave: domain
RBAC: ServerAdmin+
Enrutamiento SMTP saliente por dominio o excepción de certificado TLS (p. ej., StartTlsIgnoreCert para hosts MX de partners con certificados que no coinciden, o conector de smart host).
/api/admin/cli/objects/Route
Lista todas las rutas salientes personalizadas
/api/admin/cli/objects/Route
Crea una ruta de dominio personalizada o una anulación de TLS
/api/admin/cli/objects/Route/{domain}
Actualiza el host de destino, el puerto o el modo TLS
/api/admin/cli/objects/Route/{domain}
Elimina la ruta personalizada
domain
string
PRIMARY KEY
targetHost
string
OPCIONAL
"" (Auto DNS-MX)
targetPort
integer
OPCIONAL
25
tlsMode
string
OPCIONAL
StartTlsOptional
"StartTlsOptional""StartTlsRequired""StartTlsIgnoreCert""ImplicitTls""ImplicitTlsIgnoreCert""None"username
string
OPCIONAL
password
string
SOLO ESCRITURA (SECRETO)
hasPassword
boolean
SOLO LECTURA
false
clearPassword
boolean
SOLO ESCRITURA (SECRETO)
false
description
string
OPCIONAL
enabled
boolean
OPCIONAL
true
{
"domain": "neff.me",
"targetHost": "",
"targetPort": 25,
"tlsMode": "StartTlsIgnoreCert",
"username": null,
"description": "Shared-Hosting-MX mit abweichendem Zertifikatsnamen (Auto DNS-MX)",
"enabled": true
}
# Partner-Domain mit fehlerhaftem MX-Zertifikat per Auto-DNS-MX freigeben:
nextxch-cli create Route \
--set domain=neff.me \
--set tlsMode=StartTlsIgnoreCert \
--set description="TLS NameMismatch auf Partner-MX erlauben"
# Internes ERP-Subnetz an lokalen Connector routen:
nextxch-cli create Route \
--set domain=erp.firma.intern \
--set targetHost=10.40.2.15 \
--set targetPort=25
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Route" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"domain":"neff.me","targetHost":"","targetPort":25,"tlsMode":"StartTlsIgnoreCert","enabled":true}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Route", new
{
domain = "neff.me",
targetHost = "",
targetPort = 25,
tlsMode = "StartTlsIgnoreCert",
enabled = true
});
TransactionalSend (Singleton)
Clave: singleton
RBAC: TenantAdmin+
Controla el calentamiento progresivo de IP de 28 días, las categorías de mensajes y las cuotas horarias/diarias por proveedor del destinatario (Google, Microsoft, Yahoo/AOL, ISP alemanes, iCloud, *).
/api/admin/cli/objects/TransactionalSend/singleton
Obtiene la política activa de calentamiento de IP y de cuotas por proveedor
/api/admin/cli/objects/TransactionalSend/singleton
Actualiza el día de calentamiento, el preajuste o las cuotas por proveedor
enabled
boolean
OPCIONAL
true
warmingEnabled
boolean
OPCIONAL
false
startAtWarmingDay
integer
SOLO ESCRITURA (SECRETO)
1
currentWarmingDay
integer
SOLO LECTURA
currentWarmingPercent
integer
SOLO LECTURA
warmingDailyRampPercents
integer[]
OPCIONAL
[5,7,10,...,100]
maxDeferHours
integer
OPCIONAL
48
defaultCategory
string
OPCIONAL
transactional
"critical""transactional""notification""marketing"preset
string
SOLO ESCRITURA (SECRETO)
"warming_28d""warming_14d""production_100"categories
CategoryPolicy[]
OPCIONAL
4 Kategorien
providers
ProviderQuota[]
OPCIONAL
6 Provider-Gruppen
{
"enabled": true,
"warmingEnabled": true,
"startAtWarmingDay": 1,
"maxDeferHours": 48,
"defaultCategory": "transactional",
"preset": "warming_28d"
}
# 28-Tage IP-Warming aktivieren:
nextxch-cli update TransactionalSend --set preset=warming_28d
# Direkt auf Warming-Tag 14 vorspringen:
nextxch-cli update TransactionalSend --set startAtWarmingDay=14
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/TransactionalSend/singleton" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"preset":"warming_28d","enabled":true}'
await http.PatchAsJsonAsync(
"/api/admin/cli/objects/TransactionalSend/singleton",
new { preset = "warming_28d", enabled = true });
ReputationShield (Singleton)
Clave: singleton
RBAC: TenantAdmin+
Protección opcional de la reputación saliente: lista automática de supresión de rebotes/quejas, baja con un clic según RFC 8058, cortacircuitos de rebotes, backoff adaptativo ante 421 de los ISP y webhooks HMAC-SHA256.
/api/admin/cli/objects/ReputationShield/singleton
Obtiene la configuración actual de Reputation Shield
/api/admin/cli/objects/ReputationShield/singleton
Actualiza los indicadores de protección o aplica un preajuste
preset
string
SOLO ESCRITURA (SECRETO)
"off""recommended""strict_bulk"enableSuppressionPreCheck
boolean
OPCIONAL
false
enforceSuppressionOnSmtpRelay
boolean
OPCIONAL
false
allSuppressedBehavior
string
OPCIONAL
reject_422
"reject_422""accept_noop"autoSuppressHardBounces
boolean
OPCIONAL
false
hardBounceSuppressionDays
integer
OPCIONAL
180
autoSuppressConsecutiveSoftBounces
boolean
OPCIONAL
false
softBounceEscalationThreshold
integer
OPCIONAL
5
autoSuppressFblComplaints
boolean
OPCIONAL
false
enableOneClickUnsubscribe
boolean
OPCIONAL
false
oneClickUnsubscribeCategories
string[]
OPCIONAL
["marketing","notification"]
enableBounceCircuitBreaker
boolean
OPCIONAL
false
maxHardBouncePercent
number
OPCIONAL
5.0
maxComplaintPercent
number
OPCIONAL
0.1
allowCriticalWhenTripped
boolean
OPCIONAL
true
enableAdaptiveIspBackoff
boolean
OPCIONAL
false
ispCooldownMinutes
integer
OPCIONAL
15
webhookEnabled
boolean
OPCIONAL
false
webhookUrl
string
OPCIONAL
webhookSecret
string
SOLO ESCRITURA (SECRETO)
{
"preset": "recommended",
"enableSuppressionPreCheck": true,
"autoSuppressHardBounces": true,
"hardBounceSuppressionDays": 180,
"enableOneClickUnsubscribe": true,
"oneClickUnsubscribeCategories": ["marketing", "notification"],
"enableBounceCircuitBreaker": true,
"maxHardBouncePercent": 5.0,
"maxComplaintPercent": 0.1,
"allowCriticalWhenTripped": true,
"enableAdaptiveIspBackoff": true,
"webhookEnabled": true,
"webhookUrl": "https://erp.firma.de/webhooks/nextxch"
}
# Empfohlenen Reputationsschutz aktivieren:
nextxch-cli update ReputationShield --set preset=recommended
# Webhook-Ziel konfigurieren:
nextxch-cli update ReputationShield \
--set webhookEnabled=true \
--set webhookUrl=https://erp.firma.de/webhooks/nextxch \
--set webhookSecret=whsec_9f8e7d6c5b4a
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/ReputationShield/singleton" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"preset":"recommended"}'
await http.PatchAsJsonAsync(
"/api/admin/cli/objects/ReputationShield/singleton",
new { preset = "recommended" });
SpamGuard (Singleton)
Clave: singleton
RBAC: ServerAdmin+
Defensa de entrada en varias etapas: verificación SPF/DKIM/DMARC/ARC, Smart Greylisting (/24 IPv4 & /64 IPv6), clasificador ML en línea (FTRL-Proximal), zonas DNSBL, listas de permitidos/bloqueo y análisis TCP con ClamAV.
/api/admin/cli/objects/SpamGuard/singleton
Obtiene los umbrales de SpamGuard & los contadores de entrenamiento
/api/admin/cli/objects/SpamGuard/singleton
Actualiza in situ las puntuaciones, DNSBL, listas de permitidos o ClamAV
enableEmailAuthChecks
boolean
OPCIONAL
true
enableGreylisting
boolean
OPCIONAL
true
greylistRetryDelaySeconds
integer
OPCIONAL
240
junkScoreThreshold
number
OPCIONAL
4.5
rejectScoreThreshold
number
OPCIONAL
9.0
tagSubjectOnJunk
boolean
OPCIONAL
false
subjectTagPrefix
string
OPCIONAL
"[SPAM] "
enableStructuralHeuristics
boolean
OPCIONAL
true
dnsblZones
string[]
OPCIONAL
["bl.spamcop.net","ix.dnsbl.manitu.net"]
dnsblHitScore
number
OPCIONAL
3.5
allowedSendersOrDomains
string[]
OPCIONAL
[]
blockedSendersOrDomains
string[]
OPCIONAL
[]
clamAvEnabled
boolean
OPCIONAL
false
clamAvHost
string
OPCIONAL
"127.0.0.1"
clamAvPort
integer
OPCIONAL
3310
{
"enableEmailAuthChecks": true,
"enableGreylisting": true,
"greylistRetryDelaySeconds": 240,
"junkScoreThreshold": 4.5,
"rejectScoreThreshold": 9.0,
"enableStructuralHeuristics": true,
"dnsblZones": ["bl.spamcop.net", "ix.dnsbl.manitu.net"],
"dnsblHitScore": 3.5,
"allowedSendersOrDomains": ["datev.de", "partner-spedition.de"],
"blockedSendersOrDomains": [],
"clamAvEnabled": false,
"clamAvHost": "127.0.0.1",
"clamAvPort": 3310
}
# Partner-Domains auf die Allowlist setzen:
nextxch-cli update SpamGuard \
--set allowedSendersOrDomains=datev.de,partner-spedition.de
# Schwellenwerte anpassen:
nextxch-cli update SpamGuard --set junkScoreThreshold=4.5 --set rejectScoreThreshold=9.0
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/SpamGuard/singleton" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"junkScoreThreshold":4.5,"rejectScoreThreshold":9.0,"allowedSendersOrDomains":["datev.de"]}'
await http.PatchAsJsonAsync(
"/api/admin/cli/objects/SpamGuard/singleton",
new { junkScoreThreshold = 4.5, rejectScoreThreshold = 9.0 });
SmtpQueue (Singleton)
Clave: singleton
RBAC: ServerAdmin+
Controla la cola de entrega MX saliente, la concurrencia de workers, los intervalos de reintento, la limitación por ISP, la validación TLS saliente, el smart host global y los límites ESMTP entrantes.
/api/admin/cli/objects/SmtpQueue/singleton
Obtiene toda la configuración de cola, TLS y ESMTP
/api/admin/cli/objects/SmtpQueue/singleton
Actualiza los workers de la cola, el calendario de reintentos o los límites ESMTP en 0 ms
outboundQueuePaused
boolean
OPCIONAL
false
outboundWorkerConcurrency
integer
OPCIONAL
8
maxDeliveryAttempts
integer
OPCIONAL
10
retryScheduleMinutes
integer[]
OPCIONAL
[5,15,60,240,720]
maxConcurrentConnectionsPerMxDomain
integer
OPCIONAL
4
strictThrottleDomains
string[]
OPCIONAL
["t-online.de","gmx.de","web.de","yahoo.com"]
strictThrottleMaxConcurrency
integer
OPCIONAL
2
outboundConnectTimeoutSeconds
integer
OPCIONAL
30
outboundBindAddress
string
OPCIONAL
"" (Auto)
outboundUseStartTls
boolean
OPCIONAL
true
requireOutboundTls
boolean
OPCIONAL
false
outboundTlsCertValidation
string
OPCIONAL
Opportunistic
"Opportunistic""IgnoreErrors""Strict"outboundSmartHost
string
OPCIONAL
""
outboundSmartPort
integer
OPCIONAL
587
maxMessageSizeMb
long
OPCIONAL
50
maxRecipientsPerTransaction
integer
OPCIONAL
100
maxConnectionsPerIp
integer
OPCIONAL
20
tarpitDelayMs
integer
OPCIONAL
1500
requireTlsForAuth
boolean
OPCIONAL
true
{
"outboundQueuePaused": false,
"outboundWorkerConcurrency": 8,
"maxDeliveryAttempts": 10,
"retryScheduleMinutes": [5, 15, 60, 240, 720],
"maxConcurrentConnectionsPerMxDomain": 4,
"strictThrottleDomains": ["t-online.de", "gmx.de", "web.de", "yahoo.com"],
"strictThrottleMaxConcurrency": 2,
"outboundUseStartTls": true,
"requireOutboundTls": false,
"outboundTlsCertValidation": "Opportunistic",
"maxMessageSizeMb": 50,
"maxRecipientsPerTransaction": 100,
"tarpitDelayMs": 1500,
"requireTlsForAuth": true
}
# Outbound-TLS auf Opportunistic (RFC 7435) setzen & MaxMessageSize auf 75 MiB erhöhen:
nextxch-cli update SmtpQueue \
--set outboundTlsCertValidation=Opportunistic \
--set maxMessageSizeMb=75
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/SmtpQueue/singleton" \
-H "Authorization: Bearer smk_..." \
-H "Content-Type: application/json" \
-d '{"outboundTlsCertValidation":"Opportunistic","maxMessageSizeMb":75}'
await http.PatchAsJsonAsync(
"/api/admin/cli/objects/SmtpQueue/singleton",
new { outboundTlsCertValidation = "Opportunistic", maxMessageSizeMb = 75 });
TransportRules & Server (Singletons)
Clave: singleton
RBAC: ServerAdmin+
Aviso legal para toda la organización (insertado antes de la firma DKIM), script Sieve global de entrada, umbrales de bloqueo automático de Fail2Ban y ServerHostName canónico.
/api/admin/cli/objects/TransportRules/singleton
Obtiene la configuración de aviso legal, Sieve global y bloqueo automático
/api/admin/cli/objects/TransportRules/singleton
Actualiza las reglas de transporte in situ
/api/admin/cli/objects/Server/singleton
Obtiene ServerHostName, motor de almacenamiento, profundidad de la cola y estado de la licencia
/api/admin/cli/objects/Server/singleton
Actualiza el ServerHostName canónico en 0 ms
outboundDisclaimerEnabled
boolean
OPCIONAL
false
outboundDisclaimerExternalOnly
boolean
OPCIONAL
true
outboundDisclaimerText
string
OPCIONAL
""
outboundDisclaimerHtml
string
OPCIONAL
""
inboundSystemSieve
string
OPCIONAL
""
autoBanThreshold
integer
OPCIONAL
8
autoBanDurationMinutes
integer
OPCIONAL
30
serverHostName
string
OPCIONAL
mail.<domain>
storageProvider
string
SOLO LECTURA
Sqlite | SqlServer | Postgres
activeQueueCount
integer
SOLO LECTURA
0
licenseState
string
SOLO LECTURA
EnterpriseActive
{
"outboundDisclaimerEnabled": true,
"outboundDisclaimerExternalOnly": true,
"outboundDisclaimerText": "-- \nMuster Logistik GmbH · Industriestraße 18 · 70565 Stuttgart · HRB 774819",
"outboundDisclaimerHtml": "<p style='font-size:11px;color:#64748b'><strong>Muster Logistik GmbH</strong> · 70565 Stuttgart · HRB 774819</p>",
"inboundSystemSieve": "require [\"fileinto\"];\nif header :contains \"X-Spam-Flag\" \"YES\" { fileinto \"Junk\"; }",
"autoBanThreshold": 8,
"autoBanDurationMinutes": 30
}
# Pflicht-Impressum & Auto-Ban aktualisieren:
nextxch-cli update TransportRules \
--set outboundDisclaimerEnabled=true \
--set autoBanThreshold=8
# Kanonischen Server-Hostnamen abfragen oder setzen:
nextxch-cli get Server
nextxch-cli update Server --set serverHostName=mail.muster-logistik.de
curl -fsS -X GET "https://mail.firma.de/api/admin/cli/objects/Server/singleton" \
-H "Authorization: Bearer smk_..."
var status = await http.GetFromJsonAsync<JsonElement>("/api/admin/cli/objects/Server/singleton");
Console.WriteLine($"Host: {status.GetProperty("serverHostName")}, Queue: {status.GetProperty("activeQueueCount")}");