Skip to content

Admin API

Everything Mockifyr does at runtime is driven through /__admin. The dashboard is a client of this API and nothing more.

Tenancy

Requests carry their tenant in the X-Mockifyr-Tenant header. Absent means the default tenant. See multi-tenancy.

Terminal window
curl -H 'X-Mockifyr-Tenant: team-payments' http://localhost:8080/__admin/mappings

Authentication — HTTP Basic, off by default — is covered in securing the admin API.

Health and tenants

MethodPathPurposeResponse
GET/__admin/healthLiveness and a snapshot of the instance{name, version, persistence, tenants, totalStubs}
GET/__admin/tenantsTenants currently holding stubs{tenants:[…]}
{
"name": "Mockifyr",
"version": "1.0",
"persistence": "InMemory",
"tenants": 2,
"totalStubs": 14
}

persistence is the provider name of the configured store.

Mappings

MethodPathPurposeResponse
GET/__admin/mappingsList the tenant’s stubs{mappings:[…]}
POST/__admin/mappingsCreate a stub201 {id, uuid} · 422 on malformed or wrongly-typed JSON
GET/__admin/mappings/{id}Fetch one stub200 {id} · 404
PUT/__admin/mappings/{id}Replace in place200 {id, uuid} · 422
DELETE/__admin/mappings/{id}Delete200, idempotent
POST/__admin/mappings/importLoad a {"mappings":[…]} bundle200 · 422
POST/__admin/mappings/resetClear the tenant’s mappings200

Each entry in the GET /__admin/mappings list is the stub’s own source JSON, with id and uuid stamped in. What you wrote is what comes back.

On PUT, the route id is authoritative: an id in the body does not move the stub.

Terminal window
curl -X POST http://localhost:8080/__admin/mappings \
-d '{"request":{"method":"GET","url":"/hello"},"response":{"status":200,"body":"world"}}'
# → 201 {"id":"…","uuid":"…"}

See writing stubs.

Request journal

MethodPathPurposeResponse
POST/__admin/requests/countCount requests matching a pattern{count:n}
GET/__admin/requestsList logged requests{requests:[…]}
GET/__admin/requests/{id}Full detail for one requestsee below

The body of POST /__admin/requests/count is a request pattern built from the same matchers as a stub’s request block — see request matching. An empty pattern matches everything:

Terminal window
curl -X POST http://localhost:8080/__admin/requests/count -d '{}'
# → {"count":37}

GET /__admin/requests accepts ?unmatched=true to return only requests that no stub matched. Each list entry is a summary:

{
"requests": [
{
"id": "",
"method": "GET",
"url": "/hello",
"status": 200,
"wasMatched": true,
"stubId": "",
"loggedDate": ""
}
]
}

GET /__admin/requests/{id} returns the full exchange, including any webhooks the stub fired:

{
"id": "",
"loggedDate": "",
"wasMatched": true,
"stubId": "",
"request": { "method": "POST", "url": "/orders", "headers": [], "body": "" },
"response": { "status": 201, "statusMessage": "Created", "headers": [], "body": "" },
"webhooks": [
{
"method": "POST",
"url": "https://callback.example.com/hook",
"headers": [],
"body": "",
"delivered": true,
"response": { "status": 200, "headers": [], "body": "" },
"error": null
}
]
}

The webhooks[] array is how you confirm a callback actually went out — see webhooks.

Scenarios

MethodPathPurposeBody
GET/__admin/scenariosList scenarios and their current state
PUT/__admin/scenarios/{name}/stateForce a scenario into a state{"state":"…"}
POST/__admin/scenarios/resetReset every scenario

The state body is optional; omitted, it defaults to Started. See scenarios.

Environments

MethodPathPurpose
GET/__admin/environmentsList keys, their values and the value in effect
PUT/__admin/environments/{key}Define a key and its named values
PUT/__admin/environments/{key}/activeSwitch which named value is active
DELETE/__admin/environments/{key}Remove a key
POST/__admin/environments/resetClear the tenant’s keys
Error codeHTTP
Environment.InvalidBody400
Environment.ReservedKey400
Environment.UnknownKey404

See environments for the request and response shapes.

Recordings

MethodPathPurpose
POST/__admin/recordings/startBegin recording against a target
GET/__admin/recordings/statusCurrent recording state
POST/__admin/recordings/snapshotTurn traffic recorded so far into stubs
POST/__admin/recordings/stopStop recording

start requires a target:

Terminal window
curl -X POST http://localhost:8080/__admin/recordings/start \
-d '{"targetBaseUrl":"https://api.example.com"}'

A missing targetBaseUrl is 422. Recording is host-level, not per tenant — see record and playback.

Messages

The tenant-scoped inbox of captured mail and SMS (Email & SMS mocking). All routes honour X-Mockifyr-Tenant.

RouteEffect
GET /__admin/messagesList, newest first. Filters: channel=email|sms, recipient (case-insensitive substring over any addressee), contains (subject + bodies), matches (regex, 250 ms budget — malformed patterns filter to nothing), limit (0 = unlimited).
GET /__admin/messages/countCount under the same filters — always agrees with the list.
GET /__admin/messages/{id}One message, including raw — the wire payload byte-for-byte (full MIME for mail, the provider form body for SMS).
GET /__admin/messages/{id}/attachments/{index}Attachment bytes with the stored content type and file name.
GET /__admin/messages/otp?recipient=…&channel=…&pattern=…Extracts a one-time code from the newest matching message. Default pattern \b\d{4,8}\b; a participating capture group wins over the full match. Errors are honest: Message.NotFound, Otp.NoMatch, or 422 for an invalid pattern.
GET /__admin/messages/{id}/otp?pattern=…The same extraction against one specific message.
DELETE /__admin/messages/{id}Delete one message (404 when it is not in this tenant’s inbox).
POST /__admin/messages/resetClear the tenant’s inbox.
GET/PUT/DELETE /__admin/messages/behaviorsPer-tenant channel directives: {"smtpFault":"none|reject|drop","smtpDelayMs":0,"smsErrorCode":21211,"webhookUrl":"…"}. PUT validates (negative delay or a non-five-digit code → 422); DELETE resets to defaults.

gRPC descriptors

RouteEffect
GET /__admin/grpc/descriptorsThe loaded *.dsc files and every indexed service/method.
POST /__admin/grpc/descriptors?name=…Uploads a compiled descriptor set (raw bytes). Parse-validated before anything is written; serving hot-reloads — no restart.
DELETE /__admin/grpc/descriptors/{name}Removes the file and rebuilds the index.

Outbound trust

MethodPathPurposeResponse
GET/__admin/outbound-trustCurrent outbound TLS trust{hosts:[], trustAll, pinned, persistent}
POST/__admin/outbound-trust/hostsTrust a host — {"host":"…"}
DELETE/__admin/outbound-trust/hosts/{host}Stop trusting a host
Error codeHTTP
Trust.FlagPinned409
Trust.UnknownHost404
Trust.Unavailable501
anything else400

Git sync

MethodPathPurposeResponse
GET/__admin/git/statusSync state{configured, remote, branch, dirty, ahead, behind, fetchError, configuredBy, workingCopy, credentialsSource}
POST/__admin/git/configureSet the remote — {remoteUrl, branch?}
POST/__admin/git/credentialsStore HTTPS credentials — {token, username?}
POST/__admin/git/pushCommit and push — optional {"message":"…"}{pushed, commit, reason}
POST/__admin/git/pullFetch, merge and reload stubs{updated, commit, stubsLoaded, reason}

An empty body on POST /__admin/git/credentials clears the stored credentials. Credentials are never echoed back by any endpoint, including git/status — that response reports only credentialsSource.

Error codes

The Git mapping is worth reading before you write a client against it:

Error codeHTTP
Git.NotConfigured404
Git.NotSupported404
Git.RemoteBranchMissing404
Git.InvalidMappings422
Git.InvalidRemote422
Git.InvalidBranch422
Git.RemoteAhead409
Git.Diverged409
Git.DirtyWorkingTree409
Git.LocalOverlap409
Git.WrongBranch409
Git.FlagPinned409
Git.PersistenceConflict409
Git.Auth502

Extensions

MethodPathPurpose
ANY/__admin/ext/{**rest}Route to a registered extension

The first path segment after ext/ selects the extension whose RoutePrefix matches it. An unknown prefix is 404. See extending Mockifyr.

WebSocket endpoints

POST /__admin/message-mappings (register), GET /__admin/message-mappings (list, each entry the registration JSON with its id stamped in), DELETE /__admin/message-mappings/{id}, and POST /__admin/channels/send belong to the WebSocket facade — see WebSocket.