Docs / API Reference
REST API
The JSON API Axon.Server maps under /axon when you call
.AddAxonApiEndpoints() or .AddAxonDashboard() (which includes it).
The dashboard UI is a client of this exact API — nothing here is dashboard-only.
If .AddAuthentication(...) is configured, every endpoint below requires a signed-in session (the axon_dashboard_auth cookie) except POST /axon/login and GET /axon/me. Endpoints marked Admin additionally require the Admin role — a ReadOnly user gets 403 Forbidden. With no authentication configured, every endpoint is open to anyone who can reach the server.
Jobs
Lists jobs, newest first. All query parameters are optional.
- skip int — default 0.
- take int — default 20 (a
0or omitted value also resolves to 20, not unlimited). - state JobState? — filters to a single state, e.g.
Enqueued,Processing,Failed. Omit for all states.
Returns 200 with an array of Job objects.
Returns 200 with an array of state transitions for the job, oldest first:
[
{ "jobId": "a1b2...", "state": "Enqueued", "timestamp": 638..., "note": null },
{ "jobId": "a1b2...", "state": "Processing", "timestamp": 638..., "note": null },
{ "jobId": "a1b2...", "state": "Failed", "timestamp": 638..., "note": "System.Exception: ..." }
]
timestamp is UTC ticks (DateTime.Ticks), not Unix milliseconds. note carries the exception text on a Failed entry, otherwise null.
Requeues a job for immediate redispatch, regardless of its current state or remaining attempts. Returns 204, or 404 if the job doesn't exist.
Deletes a job permanently, regardless of its current state. Returns 204 whether or not the job existed — this endpoint doesn't check first.
Recurring jobs
Lists recurring jobs. Same skip/take defaults as /axon/jobs. Returns 200 with an array of RecurringJob objects.
Enqueues a one-off job right now, using the recurring job's stored method/arguments/device, without touching its schedule. Returns 200 with the new job's id, or 404 if the recurring job doesn't exist:
{ "jobId": "c4d5..." }
Sets IsPaused = true. The poll loop skips a paused recurring job entirely — NextRunAt is left untouched, so resuming picks up the existing schedule where it would have been rather than recomputing it. Returns 204, or 404 if it doesn't exist.
Sets IsPaused = false. Returns 204, or 404 if it doesn't exist.
Advances NextRunAt to the occurrence after the next one, without running the skipped occurrence. Returns 204, or 404 if it doesn't exist.
Deletes a recurring job's schedule (does not affect jobs it already triggered). Returns 204 whether or not it existed.
Servers and clients
Lists every known Axon.Server instance, most recently seen first:
[
{
"instanceId": "...",
"machineName": "api-7b9c",
"startedAt": 638...,
"lastSeenAt": 638...,
"servedQueues": "default,billing",
"isOnline": true
}
]
isOnline is computed at request time from how long ago lastSeenAt was — instances heartbeat periodically, and one that's stopped is not removed, just eventually shown offline.
Lists every connected device:
[
{
"deviceName": "WORKER-01_3f2a...",
"connectionId": "...",
"connectedAt": 638...,
"isProcessing": false
}
]
deviceName defaults to {Environment.MachineName}_{Guid} (see Axon.Client's connection setup) unless the client overrides it. isProcessing reflects whether this device currently has a job in the Processing state — a snapshot at request time, not push-updated.
Session
Only mapped when .AddAuthentication(...) is configured. Without it, GET /axon/me is still mapped but always returns { "username": null, "role": null }.
Body: { "username": string, "password": string }. On success, sets the axon_dashboard_auth cookie and returns 204. Returns 401 on bad credentials, or 429 if the username is currently locked out (5 failures within 5 minutes) or the calling IP has hit its own rate limit (5 attempts per 5 minutes). Every attempt — success or failure — is logged to Axon.Server.Services.AxonAuditLog.
Clears the session cookie. Returns 204.
Returns the current session's identity, or nulls if not signed in — useful for a frontend to check auth state without triggering a login redirect:
{ "username": "admin", "role": "Admin" }
Health checks
Always mapped, independent of AddAxonApiEndpoints()/AddAxonDashboard() and never behind auth — orchestrator probes typically can't authenticate anyway.
Always 200 once the process is up. Never touches the job store.
Reports the job store's health check result — 200 if Axon.Store.* can reach its backing database (or Redis, if AddRedisBackplane is configured), 503 otherwise.
Job shape
Returned by /axon/jobs and /axon/jobs/{jobId}:
{
"jobId": "a1b2...",
"deviceName": "WORKER-01_3f2a...",
"state": "Processing",
"methodName": "ChargeInvoice",
"declaringType": "MyApp.BillingJobs",
"assembly": "MyApp, Version=1.0.0.0, ...",
"arguments": ["inv_confirm_492"],
"priority": "Medium",
"queueName": "billing",
"attempts": 1,
"maxAttempts": 3,
"scheduledFor": null,
"enqueuedAt": 638...,
"processingDeadline": 638...,
"concurrencyKey": null,
"maxConcurrent": null,
"retryPolicy": null,
"parentJobId": null,
"continueOnParentFailure": false
}
All timestamp fields are UTC ticks. See JobState for the full set of state values.
RecurringJob shape
Returned by /axon/recurring-jobs:
{
"recurringJobId": "nightly-report",
"deviceName": "WORKER-01_3f2a...",
"cronExpression": "0 2 * * *",
"methodName": "SendNightlyReport",
"declaringType": "MyApp.ReportJobs",
"assembly": "MyApp, Version=1.0.0.0, ...",
"arguments": [],
"nextRunAt": 638...,
"lastRunAt": 638...,
"isPaused": false
}
Note that a recurring job's stored JobInfo fields don't currently include
priority/concurrencyKey/queueName — a job triggered
from a schedule always runs at default priority on the default queue, regardless of what was
set when the recurring job was created.