Workspaces and access

A workspace holds your team, your plan and everything you send and receive: domains, inboxes, contacts and mail. API keys, members and roles decide who can do what.

The model

You sign in with your email, so one person can belong to several workspaces. A workspace has members, a plan, and everything you read or send: domains, inboxes, contacts, templates, campaigns, webhooks and keys. Every workspace also gets a private runearc.email domain to try things on (see Quickstart); inboxes on it are ordinary inboxes of the workspace.

An API key belongs to one workspace and can be narrowed further (below). A signed in session picks the workspace with the Runearc-Workspace header. GET /v1/me returns the signed in user, the workspace's plan, usage and counts, and your role and permissions in it; GET /v1/me/workspaces lists the workspaces you belong to.

API keys

# A full access key
curl -X POST https://api.runearc.com/v1/keys \
  -H "Authorization: Bearer $RUNEARC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "name": "production" }'

# A sending key limited to one domain, and a key limited to one inbox
curl -X POST https://api.runearc.com/v1/keys -H "Authorization: Bearer $RUNEARC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "name": "app", "permissions": "sending", "domain_id": "dom_..." }'
curl -X POST https://api.runearc.com/v1/keys -H "Authorization: Bearer $RUNEARC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "name": "support bot", "permissions": "inbox", "inbox_id": "ibx_..." }'
FieldTypeDescription
namestringRequired, to recognise the key by.
permissionsstringfull (default), sending or inbox.
domain_idstringWith sending: send only from that domain (id or name).
inbox_idstringWith inbox: only that inbox. An inbox key cannot send over SMTP or use analytics, campaigns or templates.

The answer is 201 with key (id key_..., prefix, scope, permissions, last_used_at) and secret, which starts with mb_live_ and is shown once; only a hash is stored. GET /v1/keys lists keys and DELETE /v1/keys/{id} revokes one (204). Send it as Authorization: Bearer. Sending keys also work as the SMTP password; see Mail apps and forwarding.

Domain setup

RequestBodyReturns
POST /v1/setupdomain, mode, addresses201: the domain, its DNS records, inboxes, senders and a sending key.

setup adds a domain and the addresses you want in one call. mode is root (receive on the domain), subdomain (receive on mail.<domain>, leaving the root's mail alone) or sending_only; each address is { "local_part", "kind": "inbox" | "sender", "display_name" }. Publish the returned records, then verify; see Domains.

Members and roles

A member has a workspace role: owner (exactly one), admin, member or billing. Owners and admins can do everything, and billing sees billing and no mail. A member also has a member_role (admin, developer, support or viewer, default viewer) and optionally a list of inbox_ids that narrows it to those inboxes; no list means every inbox. Only owners and admins manage members.

curl -X POST https://api.runearc.com/v1/invitations \
  -H "Authorization: Bearer $RUNEARC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "email": "sam@acme.com", "workspace_role": "member",
        "member_role": "support", "inbox_ids": ["ibx_..."] }'

Invitations expire after 7 days. The invitee signs in with the invited address and accepts with the link; accepting needs a signed in session, not an API key.

RequestBodyReturns
GET /v1/membersnoneMembers: user, workspace_role, member_role, inbox_ids, joined_at, last_seen_at.
PATCH /v1/members/{user_id}workspace_role, member_role, inbox_ids (all optional)The member. inbox_ids replaces their inbox list; null or an empty list means every inbox.
DELETE /v1/members/{user_id}none204. Also revokes their app passwords.
POST /v1/members/transfer-ownershipuser_idThe new owner. Owner only.
GET, POST /v1/invitationsemail, workspace_role, member_role, inbox_idsInvitations; POST returns 201.
DELETE /v1/invitations/{id}none204. Revokes it.
POST /v1/invitations/{id}/resendnoneThe invitation, resent.
GET /v1/invitations/lookup?token=noneWhat the invite page shows. No auth.
POST /v1/invitations/accepttokenJoins the workspace. Needs a session.

Workspace settings, export and deletion

RequestBodyReturns
PATCH /v1/workspacenameThe workspace.
GET, PATCH /v1/workspace/retentionretention_days (1 to 3650, or null to keep mail until deleted), audit_retention_days (30 to 3650, default 400)The settings.
GET /v1/workspace/export?include_raw=true adds each message's .emlA streamed NDJSON file, one {type, data} object per line. Owner only.
DELETE /v1/workspaceconfirm: the workspace slugDeletes the workspace and all its data. Owner only.
GET /v1/auditaction, actor_id, from, to, after, limit 1..100A page of audit events.
GET /v1/audit/exportformat (csv or ndjson), from, toThe audit log as a file.

GET /v1/account/export and DELETE /v1/account do the same for your own user account across workspaces. The postal address for marketing mail is GET, PUT /v1/workspace/postal-address; see Onboarding.

CLI and MCP

runearc login
runearc whoami
runearc keys create production
runearc keys create app-inbox --inbox ibx_...
runearc keys list
runearc keys revoke key_...

Members, invitations and workspace settings have no CLI command or MCP tool; use the dashboard or the endpoints above with a session.

Errors

CodeStatusMeaning and fix
insufficient_scope403This key's scope is too narrow. Use a full key.
invalid_role400Use the roles listed above.
already_member, already_invited409That person is already in, or invited to, the workspace.
invitation_not_found, invitation_invalid404The link is wrong, revoked or expired. Ask for a new invitation.
invitation_email_mismatch403Sign in with the address that was invited.
session_required, session_expired401Accepting needs a signed in session.
invalid_retention400Mail 1 to 3650 days or null; audit 30 to 3650.
confirmation_mismatch, confirmation_required400Send {"confirm": "<workspace slug>"}.
Plan limits on inboxes, domains and email volume are on Sending and Errors.

Something unclear or wrong? The API answers every error with a fix, and so should these docs. Back to runearc.com