Skip to content

API reference

HTTP API

The mux API is JSON over HTTPS. It is what muxcode, the MCP server and the web app use to reach a workspace’s code index, its repositories and its sandboxes, and anything you build can use it the same way.

Every path below is under the base URL https://usemux.com/api.

Send a workspace key

A workspace key is a bearer token: Authorization: Bearer hk_live_…. Each key belongs to exactly one workspace and carries a role, and it can never do more than the person who minted it can do today. A key whose owner loses access stops working with them.

Workspace owners mint keys in the app under Settings, then Access. A key is shown once, when it is minted; mux keeps only its hash.

Roles, from least to most: viewer, agent, editor, owner. Each route below names the least role it needs.

The web app calls the same routes with the signed-in person’s session cookie instead of a key. Routes marked signed-in person accept only that: a key, however senior, is refused with 403 human_gate.

Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/workspace \
-H "Authorization: Bearer $MUX_API_KEY"

The error shape

mux answers with a conventional status code and, for every error, one JSON envelope: a stable code to branch on and a message written to be shown to a person.

  • 400 validation_error - the body or a parameter is not what the route accepts. invalid_json when the body is not JSON at all.
  • 401 unauthenticated - no key or session, or a key that is revoked or expired.
  • 403 forbidden - your role is below the route’s. human_gate when the route needs a signed-in person. plan_refused and plan_limit when the plan does not include it.
  • 404 not_found - no such thing, or one your credential cannot see. A workspace in another organization answers 404, never 403, so a key cannot learn what exists elsewhere.
  • 409 - the request conflicts with the workspace’s state, such as no_repositories or refresh_in_progress.
  • 429 - a rate limit; see below.
  • 5xx - mux or a service behind it did not answer. 503 index_unavailable is safe to retry.
Response 404
{
"error": {
"code": "not_found",
"message": "Vault not found."
}
}

Two meters per organization

Every /v1 request draws from two meters kept per organization: a per-minute burst bucket and a monthly ceiling by UTC calendar month. Each response reports both.

  • X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds) for the burst bucket.
  • X-Quota-Limit and X-Quota-Remaining for the month.

Past either meter the answer is 429 with Retry-After, and scope names the meter. burst clears within the minute. monthly clears at the start of the next UTC month, so do not retry it in a loop. This one answer is a flat body rather than the error envelope.

Device sign-in is limited by address instead, and refuses a start when the limiter cannot answer.

Plan Workspaces Repositories indexed Refresh Search by meaning Requests/min Requests/month
Hobby 1 1 on request no 30 50,000
Pro 5 20 on push yes 120 500,000
Team 25 20 on push yes 300 2,000,000
Response 429
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1727000060
{
"error": "Rate limit exceeded",
"scope": "burst",
"retryAfter": 12
}

A workspace holds the repositories you index, the people and keys that can reach it, and its sandbox runs. In the API a workspace is a vault, and its id is the vaultId in every path.

Retrieve a workspace

GET /v1/vaults/:vaultId/workspace

Who can call itviewer

Describes the workspace a key or session reaches, and what its plan lets a client offer. Read capabilities before searching: a workspace without semantic should be offered pattern search only.

Returns

plan string
free (Hobby), pro, proplus or team.
role string
The caller’s role in this workspace.
trial object | null
The caller’s trial, in the device sign-in’s shape but never with a keychainToken; null when they have none.
meters object
Where the caller stands against their caps, in the device sign-in’s shape.
capabilities object
semantic, structuralSearch and repositoryFilters. semantic is false on Hobby.
index object
The number of repositories indexed, file and chunk counts, lastSuccessAt in milliseconds, and the embeddingVersion the index was built with.
managementUrl string
Where the workspace is managed in the app.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/workspace \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
{
"managementUrl": "https://usemux.com/app/workspaces?corpus=01J9Z3K8QG",
"organizationId": "org_2Yc81",
"workspaceName": "Acme",
"corpusId": "01J9Z3K8QG",
"corpusName": "Code corpus",
"plan": "pro",
"role": "agent",
"capabilities": {
"semantic": true,
"structuralSearch": true,
"repositoryFilters": true
},
"index": {
"embeddingVersion": "Snowflake/snowflake-arctic-embed-xs",
"repositories": 2,
"files": 1234,
"chunks": 5678,
"lastSuccessAt": 1727000000000
}
}

List workspaces

GET /v1/vaults

Who can call itany key or session

A signed-in person gets every workspace they hold a grant on, oldest first, with their role in each. A key gets its one workspace, without role, or an empty list once that workspace is deleted.

Query parameters

deleted 1
Signed-in person only: list the deleted workspaces you own instead. Each can be restored for 30 days with POST /v1/vaults/:vaultId/restore.
Request
curl https://usemux.com/api/v1/vaults \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
[
{
"id": "01J9Z3K8QF",
"orgId": "org_2Yc81",
"name": "Acme",
"slug": "acme",
"createdAt": 1726500000000
}
]

One route answers every question you can ask the index. The body names an operation and its arguments, the same five tools the MCP server gives an agent, plus the code graph and context packets.

Query the index

POST /v1/vaults/:vaultId/corpus/query

Who can call itviewer

Every result carries repository, path, line, endLine, score, excerpt and the headSha it was read at; search_code results also carry language. The body is capped at 16 KiB.

Body

organizationId string required
The organization the workspace belongs to. Any other answers 404 not_found.
operation string required
One of corpus_status, list_repositories, grep_code, search_code, ask_code, get_context or trace_code.
arguments object
The operation’s arguments; see Operations below.
record boolean
false keeps the search out of the workspace’s analytics. Defaults to true.

Operations

corpus_status no arguments
Whether the workspace is indexed, its repositories and their state, the plan and its limits. Read from stored state; it never wakes the index.
list_repositories no arguments
{repositories}, each with its name and indexed headSha.
grep_code pattern · path, language, repository
A structural match against the syntax tree, not a text search. In a pattern a backslash marks a placeholder: foo(\X) is a call with one argument, foo(\(ARGS*\)) a call with any number. Answers {results, truncated}.
search_code query · limit, repository, language, path
Results ranked by meaning, so a search can find code that never uses its words. Pro and Pro+.
ask_code query
The passages that bear on a question, as grounding. It does not write the answer: answer is null, and your model reads the passages. Pro and Pro+.
trace_code repository, path · symbol, limit
One file on the code graph: what it defines, imports, is importedBy, its tests and what it is testedBy, the routes it calls and is called from, and its owners.
get_context task · repositories, revisions, changedPaths, tokenBudget, freshness
One context packet for a task; see Context packets.

query caps at 4,000 characters, pattern at 2,000, path at 400 (relative, no ..), repository at 200 as owner/name, language at 100. symbol is one plain identifier, and limit runs from 1 to 50.

Refusals

403 plan_refused Hobby
search_code and ask_code: “Semantic search is included with Pro and Pro+.”
409 no_repositories nothing chosen
grep_code, search_code and ask_code before any repository is chosen. corpus_status and list_repositories still answer 200.
503 index_unavailable retry
The index did not answer, or is waking from rest. Retry; corpus_status keeps answering.
503 graph_unavailable trace_code
The index has not written its code graph at the current commit yet. Refresh, then retry.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/corpus/query \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"organizationId": "org_2Yc81",
"operation": "search_code",
"arguments": {
"query": "retry a failed upload",
"repository": "acme/api",
"limit": 2
}
}'
Response 200
{
"results": [
{
"repository": "acme/api",
"path": "src/uploads/retry.ts",
"line": 14,
"endLine": 41,
"language": "typescript",
"score": 0.82,
"excerpt": "export async function retryUpload(job: UploadJob) {\n …",
"headSha": "9f3c2a1e4b7d…"
}
]
}
grep_code, Response 200
{
"results": [
{
"repository": "acme/api",
"path": "src/ledger.ts",
"line": 88,
"endLine": 88,
"excerpt": "split(total, accounts)",
"headSha": "9f3c2a1e4b7d…"
}
],
"truncated": false
}

Get a context packet

POST /v1/vaults/:vaultId/corpus/query

Who can call itviewer

get_context assembles what an agent should read for one task: evidence from the index, the code-graph edges between it, and the findings your workspace has approved, cut to a budget. Every packet has a receiptId you can read back, and propose findings from, for 30 days.

Arguments

task string required
The task, in words. Up to 4,000 characters.
repositories string[]
Up to 20 owner/name to read from. Defaults to every indexed repository.
revisions object[]
Pin a repository to a commit: {repository, revision}.
changedPaths object[]
Up to 20 {repository, path} your change touches; they are read first.
tokenBudget integer
From 1,024 to 16,000, default 6,000. Counted as UTF-8 bytes, an upper bound for byte-based tokenizers.
freshness string
require_current (default) answers 409 context_stale with the freshness list when an index is behind its branch. allow_stale answers from the indexed commit and names stale_or_missing_sources in omissions.

Returns

evidence object[]
Each with repository, path, line, endLine, headSha, excerpt, score, the file’s git blob, and a reason: literal, semantic, hybrid, changed-path or graph:<edge>.
relationships object[]
Code-graph edges between files in the packet - imports, tests, calls_route - each confidence: "candidate", with targetRepository and targetRevision when an edge crosses repositories.
memories object[]
Approved findings that still hold at these commits.
omissions string[]
What was left out and why: token_budget, semantic_search_not_in_plan, literal_scan_limit, changed_path_unavailable, graph_unavailable, invalid_or_out_of_scope_evidence, no_evidence.
freshness object[]
Per repository: the expected and indexed revision, and current, stale, missing or unknown.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/corpus/query \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"organizationId": "org_2Yc81",
"operation": "get_context",
"arguments": {
"task": "Add rate limiting to the public API",
"repositories": ["acme/api"],
"tokenBudget": 6000
}
}'
Response 200
{
"version": "context-v2",
"freshness": [
{
"repository": "acme/api",
"expectedRevision": "9f3c2a1e4b7d…",
"indexedRevision": "9f3c2a1e4b7d…",
"state": "current"
}
],
"evidence": [
{
"repository": "acme/api",
"path": "src/middleware/auth.ts",
"line": 1,
"endLine": 60,
"headSha": "9f3c2a1e4b7d…",
"excerpt": "export const requireKey = …",
"score": 0.77,
"reason": "hybrid"
}
],
"relationships": [],
"memories": [],
"omissions": ["token_budget"],
"tokenBudget": 6000,
"receiptId": "5b0f6c1e-…",
"retrievalMs": 412,
"expiresAt": 1729592000000
}

Propose a finding

POST /v1/vaults/:vaultId/corpus/outcomes

Who can call itagent

A finding is one sentence your agent learned, tied to the commit and files it rests on. Proposed from a context packet’s receipt, it waits for a signed-in owner to approve it with POST /corpus/memories/:memoryId/approve or /retire; a key never can. After each refresh an approved finding moves to the new commit while every file it cites is unchanged, and becomes outdated when one changes.

GET /corpus/memories lists findings: an owner sees all, others their own and the approved ones. GET /corpus/receipts/:receiptId returns a packet to whoever asked for it, and GET /corpus/trace gives a signed-in owner the 25 newest packets and the week’s figures.

Body

receiptId string required
Your own receipt, unexpired.
repository string required
owner/name.
revision string required
A headSha from that receipt.
statement string required
The finding, up to 2,000 characters.
scope string
personal or workspace.
retentionDays integer
1 to 30, default 7.
paths string[]
1 to 20 files the receipt read that the finding rests on. Defaults to every file it read there.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/corpus/outcomes \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"receiptId": "5b0f6c1e-…",
"repository": "acme/api",
"revision": "9f3c2a1e4b7d…",
"statement": "Every public route passes requireKey before its handler.",
"scope": "workspace",
"paths": ["src/middleware/auth.ts"]
}'
Response 201
{
"id": "01J9Z4B2M1",
"status": "proposed"
}

The repositories a workspace indexes come from its GitHub installation. An owner connects GitHub in the browser; after that, editors choose what to index.

List indexed repositories

GET /v1/vaults/:vaultId/repositories

Who can call itviewer

The workspace’s selection with each repository’s index state, the GitHub connection, and the plan’s limit.

Each repository

status string
mirroring, refreshing, fresh, stale or failed.
indexedSha string | null
The commit the index was built from. latestSha is the branch’s newest, and stale is true when they differ.
files, chunks integer
What the index holds for it.
error string | null
Why the last index failed, in words.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/repositories \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
{
"github": {
"configured": true,
"connected": true,
"account": "acme",
"installUrl": null
},
"canManage": false,
"plan": "pro",
"limits": { "repositories": 20 },
"refresh": "push",
"repositories": [
{
"repository": "acme/api",
"branch": "main",
"status": "fresh",
"indexedSha": "9f3c2a1e4b7d…",
"latestSha": "9f3c2a1e4b7d…",
"stale": false,
"indexedAt": 1727000000000,
"files": 120,
"chunks": 900,
"error": null
}
]
}

Choose repositories to index

PUT /v1/vaults/:vaultId/repositories

Who can call iteditor

The body is the whole selection. A repository left out is deselected, and its mirror and index entries are removed. A new one starts as mirroring.

Body

repositories object[] required
Each {repository, branch}. branch defaults to the repository’s default branch.

Refusals

404 repository_not_granted GitHub
The installation does not grant that repository.
403 plan_limit plan
More repositories than the plan indexes: one on Hobby, 20 on Pro, 50 on Pro+.
409 github_not_connected GitHub
Connect GitHub first.
Request
curl -X PUT https://usemux.com/api/v1/vaults/01J9Z3K8QF/repositories \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"repositories": [
{ "repository": "acme/api", "branch": "main" },
{ "repository": "acme/web" }
]
}'
Response 200
{
"repositories": [
{ "repository": "acme/api", "branch": "main", "status": "fresh", "…": "…" },
{ "repository": "acme/web", "branch": "main", "status": "mirroring", "…": "…" }
]
}

List what GitHub grants

GET /v1/vaults/:vaultId/github/repositories

Who can call iteditor

Every repository the GitHub installation grants, archived ones excluded, marking those already selected. Use it to offer a choice before PUT /repositories.

Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/github/repositories \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
{
"account": "acme",
"repositories": [
{
"repository": "acme/api",
"defaultBranch": "main",
"private": true,
"language": "TypeScript",
"sizeKb": 1234,
"selected": true
}
]
}

Refresh the index

POST /v1/vaults/:vaultId/corpus/refresh

Who can call iteditor

Re-indexes every selected repository, or the one you name. On Pro and Pro+ a push to an indexed branch starts this by itself. A refresh that fails for a moment is tried again after 5, 10 and 20 minutes, on every plan.

Body

repository string
owner/name. Omit it to refresh everything.

Refusals

409 refresh_in_progress busy
A refresh is already running.
429 rate_limited Retry-After: 60
A refresh was asked for less than a minute ago.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/corpus/refresh \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "repository": "acme/api" }'
Response 202
{
"started": true
}

List sandbox runs

GET /v1/vaults/:vaultId/sandboxes

Who can call itviewer

The workspace’s cloud sandbox tasks and triage runs, most recently active first, with the month’s sandbox hours. A run silent for 30 minutes reads as asleep; live counts only the running ones.

The helios-sandbox Worker records what it runs with PUT /v1/vaults/:vaultId/sandboxes/:id; who ran it is read from the credential, never the body.

Before a sandbox starts or wakes, the Worker asks POST /v1/vaults/:vaultId/sandboxes/:id/admit. Sandbox hours, sandboxes awake at once, Triage tokens and Jev are counted per person: in a team each member spends their own plan’s allowance, wherever they spend it. A start past a cap answers 402 with the cap body below; sentence is what to show the reader, and nextPlan is the plan to offer, or null on Pro+.

Response 402
{
"error": "cap",
"meter": "sandboxHours",
"plan": "pro",
"nextPlan": "proplus",
"resetsAt": 1727740800000,
"sentence": "You've used this month's 30 sandbox-hours. Pro+ has 300, 8 sandboxes at once and $10 of Jev. Upgrade or wait for 1 October."
}

Query parameters

limit integer
1 to 100, default 50.
before string
The next cursor from the previous page.
include deleted
Include deleted runs.
Request
curl "https://usemux.com/api/v1/vaults/01J9Z3K8QF/sandboxes?limit=1" \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
{
"sandboxes": [
{
"id": "3d0c1f7a-…",
"kind": "task",
"state": "asleep",
"startedBy": { "id": "usr_7Qb", "name": "Ada" },
"deviceName": "Ada's MacBook Pro",
"startedAt": 1727000000000,
"lastActiveAt": 1727003600000,
"endedAt": null,
"checkpoints": 2
}
],
"live": 0,
"next": "1727000000000.3d0c1f7a-…",
"usage": {
"hoursUsed": 3.2,
"hoursAllowed": 30,
"runningPerMember": 2,
"resetsAt": 1727740800000,
"warning": null
}
}

A Mac signs itself in rather than holding a pasted key: it asks for a code, the person approves it in the browser, and the device collects a key of its own. muxcode does this for you; build it the same way for any client.

Start a device sign-in

POST /v1/connect

Who can call itnone; limited by address

Returns a code for the person to confirm at verificationUrl. Codes last ten minutes. The browser’s half is GET /v1/connect/requests/:userCode and its approve and deny, for a signed-in person.

Body

deviceName string required
What the person will see, up to 80 characters.
client string required
muxcode.
clientVersion string
Up to 40 characters.
deviceProof object
{ uuidHash, keychainToken? }: uuidHash is the SHA-256 hex of the Mac’s hardware UUID, hashed on the device; keychainToken is the token a trial’s first sign-in returned. A Mac that sends it may start a 72-hour trial of Pro, once per device, keychain, inbox and person.
Request
curl https://usemux.com/api/v1/connect \
-H "Content-Type: application/json" \
-d '{ "deviceName": "Ada’s MacBook Pro", "client": "muxcode" }'
Response 201
{
"deviceCode": "q3V9…",
"userCode": "KQRT-7M2P",
"verificationUrl": "https://usemux.com/app/connect?code=KQRT-7M2P",
"expiresAt": 1727000600,
"interval": 3
}

Poll for the key

POST /v1/connect/poll

Who can call itthe device code

Poll at the returned interval until the person approves. The answer is a bare status: 202 pending, 429 slow_down when polled too soon, 410 denied, spent or expired. Once approved it carries the device’s own key; a code cannot be collected twice.

Beside the plan, the approved answer carries trial and meters. trial is null, or { startedAt, endsAt, jevMicroUsd, sandboxSeconds, outcome, reason? } with outcome one of live, ended, upgraded or refused; keychainToken is in it only on the answer that started the trial, or gave the Mac that started it a new one. Keep it in the keychain and send it back in deviceProof. meters is where the person stands against the caps they are held to; pooled is true in a team.

A cap body refused during a trial names plan as trial.

A device signs itself out with DELETE /v1/connect/device. An owner or admin signs out any device with DELETE /v1/organizations/:orgId/devices/:keyId.

Body

deviceCode string required
From the start.
Request
curl https://usemux.com/api/v1/connect/poll \
-H "Content-Type: application/json" \
-d '{ "deviceCode": "q3V9…" }'
Response 200
{
"status": "approved",
"baseUrl": "https://usemux.com/api",
"organizationId": "org_2Yc81",
"corpusId": "01J9Z3K8QG",
"key": "hk_live_01J9Z4C7T3…",
"workspaceName": "Acme",
"corpusName": "Code corpus",
"plan": "pro",
"role": "editor",
"trial": {
"startedAt": 1727000000000,
"endsAt": 1727259200000,
"keychainToken": "c2Vj…",
"jevMicroUsd": 0,
"sandboxSeconds": 0,
"outcome": "live"
},
"meters": {
"sandboxHoursUsed": 0,
"sandboxHoursCap": 3,
"sandboxesAwake": 0,
"sandboxesCap": 1,
"jevMicroUsdUsed": 0,
"jevMicroUsdCap": 1000000,
"resetsAt": 1727259200000,
"pooled": false
}
}

Start a trial from a signed-in Mac

POST /v1/connect/trial

Who can call itthe device's own key

A Mac already signed in asks for its trial without a second sign-in in the browser. Only a device’s key may ask, not one made by hand. The rules are the sign-in’s: once per device, keychain, inbox and person. The answer is { plan, trial, meters } in the poll’s shapes; trial.keychainToken is in it only when this call started the trial or gave the Mac that started it a new one.

Body

deviceProof object required
{ uuidHash, keychainToken? }, as sent to POST /v1/connect.

Mint a key

POST /v1/vaults/:vaultId/keys

Who can call itowner, signed-in person

Mints a workspace key. The key is in this answer only. GET /keys lists the workspace’s keys, revoked ones included, and DELETE /keys/:id revokes one; both also need a signed-in owner.

Body

role string required
viewer, agent, editor or owner.
principalType string required
agent for a program, human for a person’s own tool.
agentName string
Required for an agent key: what it is, up to 100 characters.
expiresAt integer
When it stops working, in milliseconds. Keys do not expire by default.
Request
curl https://usemux.com/api/v1/vaults/01J9Z3K8QF/keys \
-H "Cookie: $SESSION_COOKIE" \
-H "Content-Type: application/json" \
-d '{ "role": "agent", "principalType": "agent", "agentName": "ci-bot" }'
Response 201
{
"id": "01J9Z4D1K8",
"key": "hk_live_01J9Z4D1K9…",
"role": "agent",
"principalType": "agent",
"agentName": "ci-bot",
"expiresAt": null,
"createdAt": 1727000000000
}

Retrieve billing

GET /v1/billing

Who can call itany key or member

The organization’s plan, its limits and this month’s usage. GET /v1/billing/plan returns only {plan}. Changing a plan or the billing contact happens in the app, for the organization’s billing owner.

Request
curl https://usemux.com/api/v1/billing \
-H "Authorization: Bearer $MUX_API_KEY"
Response 200
{
"orgId": "org_2Yc81",
"plan": "pro",
"status": "active",
"currentPeriodEnds": 1729592000000,
"pendingPlan": null,
"cancelAtPeriodEnd": false,
"canManage": false,
"limits": {
"vaults": 1,
"apiCallsPerMin": 120,
"apiCallsPerMonth": 500000,
"semantic": true,
"indexedRepositories": 20,
"indexRefresh": "push"
},
"usage": {
"vaults": 1,
"indexedRepositories": 2,
"apiCalls": 1234
}
}

Ask Jev

POST /v1/jev/systemone

Who can call ita person's key, or a sandbox task token

Jev, the classifier, through mux. The body goes to TypeSafe’s System One as sent, and its answer comes back as it came: status, body and content type. Before the call is sent it is charged to the person’s Jev allowance ($1 a month on Pro, $10 on Pro+, $1 over a trial) at $0.042 a million input tokens, four bytes of body to a token, rounded up to a whole millionth of a dollar. Once the allowance is spent the call is not sent and the answer is 402 with the cap body, meter jev. Hobby answers 402 plan_refused. A call that TypeSafe fails or that takes longer than 15 seconds (504) stays charged. Where mux holds no Jev key the answer is 503 and nothing is charged.

Request
curl https://usemux.com/api/v1/jev/systemone \
-H "Authorization: Bearer $MUX_API_KEY" \
-H "Content-Type: application/json" \
-d @questions.json

Report a Jev call

POST /v1/jev/usage

Who can call ita person's key

muxcode reports each call it made to Jev on its own key, and is told where the person stands against the month’s Jev allowance. A call is priced as POST /v1/jev/systemone prices it, and is counted even past the cap, since it was already made; a call sent through systemone is charged there and is not reported again. inputBytes of 0 charges nothing and only asks where the person stands. Hobby records nothing: Jev runs on the person’s own keys there. refusal is the cap body once over is true.

Body

inputBytes integer required
The bytes sent to the classifier, or 0 to ask without charging.
Response 200
{
"jevMicroUsdUsed": 42000,
"jevMicroUsdCap": 1000000,
"over": false,
"refusal": null
}

Tell us what you're building

POST /v1/feedback

Who can call ita person on Pro+

A Pro+ reader at a cap writes to hello@usemux.com. Any other plan answers 403.

Body

text string required
What they are building, up to 5,000 characters.
meter string
The meter they hit: sandboxHours, sandboxesAwake or jev.
Response 202
{ "accepted": true }

The web app manages workspaces, people, GitHub and billing through these routes. They need a signed-in person unless noted, and are listed so every route is accounted for.

Method Path Who Purpose
POST /v1/workspaces person Create an organization and its first workspace
POST /v1/vaults org owner Create a workspace; body: name
PATCH /v1/vaults/:vaultId owner Rename a workspace
DELETE /v1/vaults/:vaultId owner Delete a workspace; kept for 30 days
POST /v1/vaults/:vaultId/restore org owner Restore a deleted workspace within 30 days
GET /v1/vaults/:vaultId/grants owner Who can reach the workspace
POST /v1/vaults/:vaultId/grants owner Grant a member access; body: email, role
DELETE /v1/vaults/:vaultId/grants/:principalId owner Revoke a grant
GET /v1/vaults/:vaultId/analytics viewer Home’s charts; days: 7, 30 or 90
GET /v1/organizations/:orgId/members member Members, pending invitations, signed-in Macs
POST /v1/organizations/:orgId/invitations owner or admin Invite a person; body: email, role
DELETE /v1/organizations/:orgId/invitations/:id owner or admin Cancel an invitation
DELETE /v1/organizations/:orgId/devices/:keyId member (own) or admin Sign a device out
GET /v1/organizations/:orgId/github org owner GitHub connection state
POST /v1/organizations/:orgId/github/install org owner Start the GitHub App installation, or link one with {"link":true}
POST /v1/organizations/:orgId/github org owner Finish the installation from GitHub’s callback
DELETE /v1/organizations/:orgId/github org owner Disconnect GitHub and drop its selections
POST /v1/billing/checkout billing owner Start a checkout; body: plan
GET /v1/billing/checkout/:checkoutId billing owner Confirm a checkout return
POST /v1/billing/change-plan billing owner Change a paid plan
POST /v1/billing/keep-plan billing owner Drop a scheduled plan change
POST /v1/billing/transfer-owner billing owner Hand billing to another member
POST /v1/billing/cancel billing owner Cancel at the period’s end
POST /v1/billing/reactivate billing owner Undo a pending cancellation
POST /v1/billing/portal billing owner Open the billing portal
POST /v1/billing/webhook Polar signature Billing events
POST /v1/webhooks/github-app GitHub signature Push and installation events; a push to an indexed branch marks it stale