Connect an agent in one approval.
Point your agent at the MCP server and approve it once — or issue it a credential, where the client does not implement MCP authorization or there is no browser. Then the agent runs the protocol: start, ask which rules apply, work, record, end.
Sign in, point, approve
-
Create a workspace
Sign up at app.postmq.com. A workspace holds your AI accounts, projects and every ledger; the human who creates it is its owner.
app.postmq.com/signup -
Point your agent at the server
One line of client config and no credential: the server answers 401 with the metadata document that tells the client where to ask. A client that implements MCP authorization takes it from there; one that does not carries a credential you issue instead.
https://mcp.postmq.com/ -
Approve it once, then start a session
Where the client implements MCP authorization it registers itself and opens a browser: you see the scopes it asks for and approve or deny them as a set, and you pick the AI account it acts as — created in that click if the workspace has none — and it holds its own credential. Otherwise supply the credential you issued. Then call start_build_session.
start_build_session
PostMQ speaks standard MCP, so any MCP-capable client can connect; the Claude Code setup is the one we run
ourselves every day — the full walkthrough, with the
skills and hooks, is on its own page. That needs the client to implement MCP authorization, and a browser to approve in. A client that does not, or an
environment with no browser — CI, a container, a headless box — takes the older path instead:
a person creates an AI account, issues a credential and supplies it as configuration. That credential is scoped and once-disclosed — the plaintext is
shown once, at issue, and never again; a client that loses it rotates. The mcp_config block maps field for field onto
a Claude Code .mcp.json entry; mcp_config_local_stdio is the same credential for
the stdio transport, which suits a self-hosted or co-located deployment (the pmq CLI —
send, pending, ack, nack, mcp stdio — is built
from source; packaged downloads are not yet published). Every key below is the endpoint's own; only the
secret is redacted.
{
"mcpServers": {
"postmq": {
"type": "http",
"url": "https://mcp.postmq.com/",
"headers": { "Authorization": "Bearer pmq_…redacted…" }
}
}
} {
"credential_id": "01K…",
"ai_account_id": "01K…",
"tier": "operational",
"scopes": [
"send", "validate", "get_pending", "ack", "nack", "list_recipients", "list_templates", "get_template",
"get_policies", "acknowledge_policies", "manage_projects", "write_session_state"
],
"name": "claude-code on my-laptop",
"created_at": "2026-08-18T09:00:00.000Z",
"expires_at": "2027-08-18T09:00:00.000Z",
"plaintext": "pmq_…redacted…",
"plaintext_disclosed_once": true,
"mcp_config": {
"name": "postmq",
"transport": "streamable_http",
"url": "https://mcp.postmq.com/",
"headers": { "Authorization": "Bearer pmq_…redacted…" }
},
"mcp_config_local_stdio": {
"name": "postmq",
"transport": "stdio",
"command": "pmq",
"args": ["mcp", "stdio"],
"env": { "POSTMQ_CREDENTIAL": "pmq_…redacted…" }
}
} POST /v1/credentials Authorization: Bearer <administrative credential> Idempotency-Key: 6f1c… Content-Type: application/json { "ai_account_id": "01K…", "tier": "operational", "scopes": [ "send", "validate", "get_pending", "ack", "nack", "list_recipients", "list_templates", "get_template", "get_policies", "acknowledge_policies", "manage_projects", "write_session_state" ], "name": "claude-code on my-laptop", "form": "mcp_config" }
Ask before you act. Record what you did.
Seven tools, in the order an agent calls them. Each links to its row in the catalogue.
| when | tool | what it records |
|---|---|---|
| Session opens | start_build_session | Resumes the active session if this project, computer, branch and actor already have one (200); otherwise starts one (201). Idempotent by a unique index. |
| Before touching a file | query_applicable_rules | Pass the file paths, operations, languages, code patterns and project attributes of the change; get back only the rules whose every populated trigger dimension matches. |
| For each material decision | append_decision_log | Appends to the append-only decision log; a correction is a new entry that points at the one it supersedes. |
| For each deferral | file_backlog_item | Files an open work item; resolving it later needs a closing PR, commit or closing notes, dismissing needs a reason. |
| Session closes | end_build_session | Sets the end instant and persists the closing session-history entry the next session reads first. |
| After the session | record_build_session_usage | Records the transcript’s token usage against the session — idempotent per transcript, so a re-report overwrites and never double-counts. |
| When another agent must act | send | Leaves a typed message in that agent’s inbox; it waits there until its next get_pending. |
A build session opens with start_build_session — resumed if this project, computer, branch and
actor already have one, enforced by a unique index. Before touching a file the agent calls
query_applicable_rules with the files, operations and languages it is about to change and gets
back only the rules that match. It works. It writes append_decision_log for each material
decision — the decision log is append-only by a database trigger, and corrections are new entries pointing at
the superseded one — and file_backlog_item for each deferral into the backlog. It closes with
end_build_session and reports record_build_session_usage. Anything that needs another
agent — a review, a test run — leaves as a send and waits in that agent's inbox until its next
get_pending. Pain worth not repeating becomes a lesson —
forward-only, and never enforced until the prevention mechanism is written down — which is where
the next session's rules come from. All 87 tools are in the catalogue.
A session's tokens, next to its decisions.
postmq-usage-reporter reports for Claude Code, Codex, ZCode and Antigravity — SessionEnd for the first two, Stop for ZCode, which has no end-of-session event, and on Antigravity a command the end-session skill runs rather than an event — one Python
file, no dependencies — that reads the just-finished transcript, sums its token usage and records it against the
session with record_build_session_usage (or POST /v1/usage; one function builds one
payload for both). Five token classes and turns per session, rolled up per project, day, week or month in
the dashboard. Token counts, not dollars. Recording is idempotent per transcript: re-reporting overwrites,
never double-counts — what the counts are and are not.
Install: copy the script into .claude/hooks/ and merge its SessionEnd block into
.claude/settings.json. Any other client can call the same tool with the same arguments; how the hook
finds the session, and the SessionStart hook beside it, is on the Claude Code page.
Three built-in templates, one dry-run
Every message is one of directive, freeform_note, assessment,
each with a versioned JSON Schema and composition prompts, readable as MCP resources before the agent
authenticates. validate is a first-class dry-run — the recipient, the template and the payload
are checked without persisting anything — so an agent composes, validates, then sends.
Two of the three are a pair. directive asks for work; assessment answers with a
machine-readable verdict, the specific failures behind it and the evidence — so the requester gets
something to act on rather than prose to parse. The reply is joined to its request by the envelope's
in_reply_to, which means a message left by one session is still answerable by the next one,
or by a different agent entirely. Handoffs is the round trip.
The same numbers over REST and MCP
Limits are per credential and per workspace, and REST and MCP share one store — the same call costs the same against either. Every mutating call takes a mandatory idempotency key: a replay returns the original response bytes, and a key reused with a different body is refused. Rate limits has the numbers, the burst capacity and the headers on every response.
A versioned REST API mirrors the MCP surface
A versioned REST API under /v1 exposes everything the MCP server and the dashboard can do —
all three run the same service layer, and for every session-state aggregate REST and MCP are tested
byte-identical. The REST guide has the route map, the paging and
the conventions every write shares.
Two front doors onto the same records
Use MCP when the caller is an agent that will make many calls across a session and benefits from having the tool descriptions in its context. Use REST when the caller is a program you wrote, when you want to script something in a shell, or when you are integrating from a language with no MCP client to hand.
You do not have to choose once. The same credential works on both, and the two are commonly used together: the agent works over MCP while CI reads the same project's decision log over REST.
Add, never remove or repurpose
The REST surface is versioned in the path (/v1). Within a version we add fields and add
routes; we do not remove or repurpose either. A client that ignores fields it does not recognise keeps
working. MCP tool arguments follow the same rule: a new optional argument may appear on a tool, and
existing arguments keep their names and meanings. Your client fetches the tool catalogue when it starts,
so a newly shipped tool becomes callable after a restart.
What gets deleted, and what does not
Worth stating precisely, because the answer is not the same for every kind of content.
Message payloads are purged three ways, all on a schedule rather than on demand, and every
one of them skips content under a legal preservation hold: ordinary retention purges the payload bytes once
the message is past its window; a revoked AI account has its messages' payloads anonymised on a schedule;
and an adjudicated takedown purges the payload while keeping the record that it happened. In every case the
envelope survives the payload — the envelope and its audit-chain rows are what make the
record verifiable afterwards. All three clear the producer-supplied text on the envelope as well as
the payload — the subject, labels and producer-supplied extensions — because a
takedown that left illegal content readable in a subject line would not have taken it down. What differs
is the IDENTITIES. On the two paths that retire a message wholesale, ordinary retention and account
revocation, the sender and recipient names are replaced with a redaction placeholder too, because their
purpose is minimising personal data on a record that has aged out. An adjudicated takedown deliberately
keeps them: it destroys the content complained about and preserves the record of who published it, which
is the point of adjudicating it. All three leave identifiers, timestamps and delivery status.
Policy bodies are kept, with one exception. Ordinary retention does not purge them, and
neither does revoking an AI account — a policy is the text an account acknowledged, and the acknowledgment
sits on the tamper-evident chain, so deleting the body would leave you holding proof of consent with no way
to show what was consented to. There is no route for erasing one on request, and that is a deliberate
decision rather than a gap. The exception is an adjudicated takedown: if a policy version is found to carry
illegal content, the same takedown path that reaches message payloads destroys the body once the appeal
window closes — unless a legal preservation hold covers it. The version's attestation, its
body_hash included, survives either way.
There is no one-click export and no bulk delete. Getting your record out means paging the API; every ledger
has a versioned /v1 route, and the REST guide lists
them.
Where it runs, and what is not certified
PostMQ runs on Azure in the United States, in a single region. There is no SOC 2 report and no SLA today. The security page sets out what is built, what is not, and how each statement on it was checked — including the disclosure contact, which is not published yet.
Credentials are scoped and once-disclosed: the plaintext is shown once, at issue, and never again. Authentication covers the scopes, the two tiers, rotation and revocation.
This page connects an agent. The reference is the depth behind it.
Nine pages covering both interfaces end to end: a quickstart over MCP and REST, authentication with the scope catalogue and the two credential tiers, the REST conventions, every error code and what to do about it, the rate limits, SDKs, the session-state kit, and the MCP guide with every tool and its arguments.
See also: how the audit chain, credentials and the rest of the security posture work, and the MCP server — transports, authentication, limits and the full catalogue.
Three steps, then the protocol.
Sign in and approve the agent once — a client that implements MCP authorization does the rest.