Mursil.Server exposes the product API under /api/v1/mursil. In Development it also maps an OpenAPI document and a Scalar reference UI. The .NET client of the send, push, and status subset is Mursil.Integration.

Health for the process is GET /health.

Authentication

Send a bearer token whose audience is mursil-api. Scopes:

ScopeAllows
mursil.messages.sendSend, batch send, cancel, status, engagement, and inbound replies.
mursil.templates.manageTemplate routes, preview, lint, test send, and brand profiles.

A portal role is an alternative to the matching scope. The claim type is role.

PolicyRoles
ViewerSystemAdmin, TenantOwner, TenantAdmin, TemplateEditor, Operator, Viewer
Template managementSystemAdmin, TenantOwner, TenantAdmin, TemplateEditor, plus the templates scope
OperatorsSystemAdmin, TenantOwner, TenantAdmin, Operator
Tenant ownerSystemAdmin, TenantOwner

Application routes also require scope headers:

HeaderWhen
X-Mursil-ApplicationIdAlways, unless the token already carries the application id.
X-Mursil-ClientIdWhen the token has no client_id, azp, or sub.
X-Mursil-TenantIdOnly when Mursil:MultiTenancy is true, and the token has no tenant_id.

While multi-tenancy is false the server ignores a caller-supplied tenant id.

Missing scope returns 400 with code HeadersRequired.

Send and status

MethodPathAuthPurpose
POST/messages/emailsendAccept one template email. Returns 202 and messageRequestId, state, correlationId.
POST/messages/email/batchsendAccept many recipients for one template key.
POST/messages/email/testtemplatesTest send from the portal or a template tool.
GET/messages/statussendLook up by messageRequestId, idempotencyKey, or correlationId.
POST/messages/{messageRequestId}/cancelsendCancel a message that has not been dispatched.
POST/messages/{messageRequestId}/engagementsendRecord an engagement event from a trusted caller.
POST/messages/repliessendRecord an inbound reply.

The send body is documented in First send. Status returns messageRequestId, state, templateKey, templateVersionId, providerKind, and failure.

Templates

All of these require template management.

MethodPathPurpose
GET/templatesList templates. Query page, pageSize.
POST/templatesCreate a template.
GET/templates/{templateId}Read one template, its variables, and its versions.
POST/templates/pushUpsert a draft from templateKey, locale, subject, html, text, and modelSchema.
POST/templates/lintLint a body without saving.
POST/templates/previewRender a body against a model without sending.
POST/templates/catalog/importImport the starter catalog.
GET/templates/{templateId}/bundleExport a bundle.
POST/templates/bundlesImport a bundle.
GET/templates/{templateId}/diffCompare leftVersion and rightVersion.
GET/templates/{templateId}/locale-coverageLocales present on the template.
POST/templates/{templateId}/locale-previewRender several locales.
POST/templates/{templateId}/versionsAdd a version.
POST/templates/{templateId}/versions/{versionId}/submit-reviewMove a draft to review.
POST/templates/{templateId}/versions/{versionId}/approveApprove a version in review.
POST/templates/{templateId}/versions/{versionId}/publishPublish.
POST/templates/{templateId}/versions/{versionId}/pausePause a published version.
POST/templates/{templateId}/versions/{versionId}/resumeResume a paused version.
PUT/templates/{templateId}/versions/{versionId}/brandingBind branding on that version.

Brand profiles

Template-management authorization.

MethodPathPurpose
GET/brand-profilesList profiles.
POST/brand-profilesCreate. Name, from-name, and theme JSON are required.
PUT/brand-profiles/{brandProfileId}Update.
POST/brand-profiles/{brandProfileId}/activateMake the profile active.

Providers and sender domains

MethodPathAuthPurpose
GET/providersoperatorsList connections.
GET/providers/kindsoperatorsSelectable kind names.
POST/providerstenant ownerCreate. Body is name, kind, settingsSecretReference, and optional webhookSigningSecretReference.
POST/providers/{providerConnectionId}/pauseoperatorsPause.
POST/providers/{providerConnectionId}/resumeoperatorsResume.
POST/providers/{providerConnectionId}/routingoperatorsSet optional purpose and region.
POST/providers/{providerConnectionId}/eventssigned, anonymous OIDCIngest a provider callback. Headers X-Mursil-Provider-Signature and X-Mursil-Provider-Timestamp.
GET/sender-domainsoperatorsList domains.
GET/sender-domains/{senderDomainId}operatorsRead one domain.
POST/sender-domainsoperatorsCreate from { "domainName": "mail.example.com" }.
GET/sender-domains/{senderDomainId}/lookupoperatorsDNS lookup.
POST/sender-domains/{senderDomainId}/verifyoperatorsVerify. Body is { "actor": "<operator>" }.

Operations, applications, and recipients

MethodPathAuthPurpose
GET/dashboardviewerDashboard figures.
GET/dashboard/watchlistviewerWatch list.
GET/dashboard/operator-action-queueviewerItems waiting on an operator.
GET/dashboard/delivery-healthviewerDelivery health.
GET/dashboard/recipient-domain-failuresviewerFailures grouped by domain.
GET/messages/deliveries/triageoperatorsFailure and triage list.
GET/messages/deliveries/{deliveryId}operatorsOne delivery.
POST/messages/deliveries/{deliveryId}/retryoperatorsRetry.
POST/messages/deliveries/{deliveryId}/suppressoperatorsSuppress.
POST/messages/deliveries/{deliveryId}/resolveoperatorsResolve.
GET/auditoperatorsAudit records. page, pageSize.
POST/retention/rendered-content/purgeoperatorsPurge stored rendered bodies.
GET/applications/controlsoperatorsSandbox, rate limit, default provider.
POST/applicationstenant ownerCreate an application.
POST/applications/sandboxoperatorsSet sandbox.
POST/applications/rate-limitoperatorsSet sends per minute.
POST/applications/default-provideroperatorsSet the default connection.
POST/tenants/engagement-trackingtenant ownerEnable or disable open and click tracking.
GET/suppressions/exportoperatorsExport suppression rows.
POST/suppressions/importoperatorsImport { scope, reason, recipientHash } rows.

Anonymous recipient routes

These sit outside the /api/v1/mursil prefix, except one-click unsubscribe.

MethodPathPurpose
GET/t/o/{token}Open pixel. Returns a transparent GIF.
GET/t/c/{token}Click redirect.
GET/p/{token}Preference center page.
POST/p/{token}Preference center form.
POST/api/v1/mursil/preferences/one-clickOne-click unsubscribe.

Tokens are signed with Mursil:Tracking. They are not a tenant id and not a session.