organization.md


title: "Organization" description: "Read, update and delete your MachineMail organization, invite and manage its members, and check the plan, its allowances and usage in the current period." canonical: "https://machinemail.dev/docs/reference/api/organization"

Organization

Read, update and delete your MachineMail organization, invite and manage its members, and check the plan, its allowances and usage in the current period.

Source: https://machinemail.dev/docs/reference/api/organization

Method Path Summary
GET /v0/organization Get Organization (alias)
GET /v0/organizations Get Organization
PATCH /v0/organizations Update Organization
DELETE /v0/organizations Delete Organization
POST /v0/organizations/deletion Start Deleting Organization
GET /v0/organizations/invitations List Invitations
POST /v0/organizations/invitations Invite Member
DELETE /v0/organizations/invitations/{invitation_id} Revoke Invitation
POST /v0/organizations/invitations/{invitation_id}/resend Resend Invitation
GET /v0/organizations/members List Members
PATCH /v0/organizations/members/{user_id} Update Member
DELETE /v0/organizations/members/{user_id} Remove Member
GET /v0/organizations/usage Get Plan Usage

Get Organization (alias)

GET /v0/organization

Alias of GET /v0/organizations.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Response

200 The organization (application/json)

Field Type Description
organization_id string required ID of the organization.
name string required Name of the organization.
slug string required URL-safe name of the organization, chosen from its name when it is created. It never changes, not even when the organization is renamed. {slug}@ on the shared domain is reserved for this organization: no other organization can create that inbox.
plan "free" | "pro" | "team" | "scale" required Plan of the organization.
inbox_count integer required Number of inboxes in the credential scope.
domain_count integer required Number of domains in the organization.
domain_limit integer Custom domains included in the plan. The Free plan cannot add more; paid plans can, and each extra domain is billed. Always present on GET /v0/organizations and PATCH /v0/organizations.
usage object Usage. Always present on GET /v0/organizations and PATCH /v0/organizations.
shared_domain string Domain every organization can create inboxes on, used when an inbox is created without domain. Always present on GET /v0/organizations and PATCH /v0/organizations.
undo_send boolean required Undo send in the dashboard: when true (the default), a message sent from the MachineMail dashboard waits 5 seconds before it goes out, so it can be undone. Only the dashboard reads it: the API, the MCP server and the CLI always send at once.
default_inbox_id string | null required The default inbox of the organization (its inbox_id). A new organization gets {slug}@ on the shared domain, named after the organization, as its default inbox; when that address cannot be used (a reserved name), it starts without one. The dashboard lists the default inbox first. Change it with PATCH /v0/organizations. null when there is none: it was cleared, its inbox was deleted, or (for a pod or inbox credential) it is outside the credential scope.
updated_at string (date-time) required Time at which the organization was last updated.
created_at string (date-time) required Time at which the organization was created.

Errors

Status Meaning
401 Missing, invalid, expired or revoked credential.
500 Unexpected server error.

Example

curl "https://api.machinemail.dev/v0/organization" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "name": "Production",
  "slug": "string",
  "plan": "free",
  "inbox_count": 1,
  "domain_count": 1,
  "domain_limit": 1,
  "usage": {
    "message_count": 1,
    "storage_bytes": 2048,
    "messages_received_30d": 1,
    "messages_sent_30d": 1
  },
  "shared_domain": "string",
  "undo_send": true,
  "default_inbox_id": "acme@machinemail.dev",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z"
}

Get Organization

GET /v0/organizations

The organization of the credential, with inbox and domain counts and usage. inbox_count and usage count what the credential can see (a pod key: its pod).

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Response

200 The organization (application/json)

Errors

Example

curl "https://api.machinemail.dev/v0/organizations" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Update Organization

PATCH /v0/organizations

Rename the organization, turn undo send in the dashboard on or off (undo_send), or change the default inbox (default_inbox_id).

The organization slug is fixed when it is created and never changes: a different slug in the body is 400 (the current value is accepted and ignored). The slug reserves {slug}@ on the shared domain for this organization.

Organization-scoped credentials only: pod and inbox credentials get 403.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Request body

Content type: application/json.

Field Type Description
name string New name. Must not be blank.
slug string Immutable: the slug is fixed when the organization is created. Only the current value is accepted (a client echoing the organization back); any other value is a 400.
undo_send boolean Undo send in the dashboard: when true (the default), a message sent from the MachineMail dashboard waits 5 seconds before it goes out, so it can be undone. Only the dashboard reads it: the API, the MCP server and the CLI always send at once.
default_inbox_id string | null Make this inbox (an inbox_id of the organization) the default inbox, or null to have none. An unknown inbox is a 404.

Response

200 The organization (application/json)

Errors

Status Meaning
400 Invalid request: error.type is validation and error.param names the field.
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404 Not found. Also returned for resources outside the credential scope.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl -X PATCH "https://api.machinemail.dev/v0/organizations" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Production"
}'

Delete Organization

DELETE /v0/organizations

Delete the organization, with the code emailed by POST /v0/organizations/deletion. It cannot be undone.

Access ends at once: every member's dashboard sessions and open streams for the organization stop working, every API key is revoked, connected apps and agents are disconnected, pending invitations are revoked, webhooks stop, and mail to the organization's addresses is refused as unknown. Its inboxes, messages, attachments, drafts, threads, domains, webhooks, events, pods and lists are then removed in the background. The slug stays reserved: no organization can use it again. Your session moves to another organization you belong to (as when leaving one); when there is none, it ends and the mm_session cookie is cleared.

Owners only, from a dashboard session (the mm_session cookie): admins, members, API keys and access tokens get 403.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Request body

Content type: application/json.

Field Type Description
code string required The 6-digit code from the email.

Response

200 Deleted (application/json)

Field Type Description
ok true required
organization_id string required ID of the deleted organization.

Errors

Error bodies use the error envelope.

Example

curl -X DELETE "https://api.machinemail.dev/v0/organizations" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "123456"
}'
{
  "ok": true,
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e"
}

Start Deleting Organization

POST /v0/organizations/deletion

First step of deleting the organization: send confirm_name, the organization's name (any case), and a 6-digit confirmation code is emailed to you. The code works once, for 10 minutes and 3 tries; asking again sends a new one (at most 3 an hour, and 10 a day for the organization). 502 when the email could not be sent: no code exists, try again. Then confirm with DELETE /v0/organizations.

409 with code: billing_subscription_active while a paid plan is in force: cancel it under Billing first, and delete the organization once the plan has ended.

Owners only, from a dashboard session (the mm_session cookie): admins, members, API keys and access tokens get 403.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Request body

Content type: application/json.

Field Type Description
confirm_name string required The name of the organization, exactly as it is shown (case and spaces included).

Response

202 Code sent (application/json)

Field Type Description
email string required Where the code was sent: your own address, partly hidden.
expires_at string (date-time) required When the code stops working (10 minutes after it was sent).

Errors

Status Meaning
400 Invalid request: error.type is validation and error.param names the field.
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
409 Conflicts with an existing resource.
429 Rate limited.
500 Unexpected server error.
502 The email provider refused or failed the send (error.type is upstream_error). Nothing was sent and no message was stored. error.message says why: a rejected message or recipient is final, and so is a used-up sending quota until it resets; a throttled or unavailable provider can be retried later. A scheduled draft whose send fails this way is marked send_status: failed, unless the provider could not take mail for now (throttled, sending paused, quota used up, or unavailable): it stays scheduled and is retried.

Error bodies use the error envelope.

Example

curl -X POST "https://api.machinemail.dev/v0/organizations/deletion" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "confirm_name": "string"
}'
{
  "email": "agent@machinemail.dev",
  "expires_at": "2026-10-01T12:00:00.000Z"
}

List Invitations

GET /v0/organizations/invitations

Pending invitations, newest first (ascending=true: oldest first). Dashboard session only (the mm_session cookie): API keys and access tokens get 403. Owners and admins manage members; only owners grant, change or remove the owner role.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Query parameters

Field Type Description
limit integer Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_token string next_page_token from the previous page.
ascending boolean Sort oldest first.

Response

200 Pending invitations (application/json)

Field Type Description
count integer required Number of items returned.
limit integer Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_token string Page token for pagination. Absent on the last page.
invitations Invitation[] required Pending invitations, newest first.

Each item of invitations is a Invitation:

Field Type Description
invitation_id string required ID of the invitation.
organization_id string required ID of the organization the invitee joins.
email string required Address the invitation was sent to. Only this address can accept it.
role "owner" | "admin" | "member" required Role in the organization. Owners and admins invite, change roles and remove members; only owners grant or remove the owner role, and an organization always keeps one owner.
state "pending" | "accepted" | "expired" | "revoked" required State of the invitation.
invited_by_user_id string ID of the member who sent it, when known.
expires_at string (date-time) required When the invitation stops working (7 days after it was sent).
created_at string (date-time) required When the invitation was sent.

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/organizations/invitations" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "invitations": [
    {
      "invitation_id": "string",
      "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
      "email": "agent@machinemail.dev",
      "role": "owner",
      "state": "pending",
      "invited_by_user_id": "string",
      "expires_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z"
    }
  ]
}

Invite Member

POST /v0/organizations/invitations

Email an invitation to join the organization, valid for 7 days and only for that address. 409 when the address is already a member or already invited.

The email links to /invite/{token}, where the person signs in (email code, social or SSO) and accepts it.

403 with error.code signup_address_not_allowed when the address is on a MachineMail domain (the shared domain, or a subdomain of it): those addresses can’t be used for accounts. The answer depends on the address’s domain only, never on whether it has an account. An address on a custom domain verified on MachineMail can be invited, but someone without an account can accept only an invitation from the organization that verified the domain; those people can join that organization but not create organizations of their own.

Dashboard session only (the mm_session cookie): API keys and access tokens get 403. Owners and admins manage members; only owners grant, change or remove the owner role.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Request body

Content type: application/json.

Field Type Description
email string required Address to invite.
role "owner" | "admin" | "member" Role on joining. Default member. Only owners can invite owners.

Response

201 Sent (application/json)

Errors

Status Meaning
400 Invalid request: error.type is validation and error.param names the field.
401 Missing, invalid, expired or revoked credential.
402 The plan allows no more members: members plus pending invitations are at its seat limit (Free: 1; limit_key: "seats"). Existing members are kept.
403 Not allowed to invite members, or the address is on a MachineMail domain (error.code signup_address_not_allowed).
409 Conflicts with an existing resource.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl -X POST "https://api.machinemail.dev/v0/organizations/invitations" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "agent@machinemail.dev"
}'
{
  "invitation_id": "string",
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "email": "agent@machinemail.dev",
  "role": "owner",
  "state": "pending",
  "invited_by_user_id": "string",
  "expires_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z"
}

Revoke Invitation

DELETE /v0/organizations/invitations/{invitation_id}

Revoke a pending invitation: its link stops working. Dashboard session only (the mm_session cookie): API keys and access tokens get 403. Owners and admins manage members; only owners grant, change or remove the owner role.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Path parameters

Field Type Description
invitation_id string required ID of the invitation.

Response

200 Revoked (application/json)

Field Type Description
ok true required

Errors

Status Meaning
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404 Not found. Also returned for resources outside the credential scope.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl -X DELETE "https://api.machinemail.dev/v0/organizations/invitations/string" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "ok": true
}

Resend Invitation

POST /v0/organizations/invitations/{invitation_id}/resend

Send a pending invitation again. Dashboard session only (the mm_session cookie): API keys and access tokens get 403. Owners and admins manage members; only owners grant, change or remove the owner role.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Path parameters

Field Type Description
invitation_id string required ID of the invitation.

Response

200 Sent again (application/json)

Errors

Error bodies use the error envelope.

Example

curl -X POST "https://api.machinemail.dev/v0/organizations/invitations/string/resend" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "invitation_id": "string",
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "email": "agent@machinemail.dev",
  "role": "owner",
  "state": "pending",
  "invited_by_user_id": "string",
  "expires_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z"
}

List Members

GET /v0/organizations/members

The people who sign in to the dashboard for this organization, with their role in it, oldest first. Organization-scoped credentials only: pod and inbox credentials get 403.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Query parameters

Response

200 A page of members (application/json)

Field Type Description
count integer required Number of items returned.
limit integer Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_token string Page token for pagination. Absent on the last page.
members Member[] required Oldest first unless ascending=false.

Each item of members is a Member:

Field Type Description
user_id string required ID of the user.
email string required Email address the user signs in with.
name string | null Display name, when set.
organization_id string required ID of the organization this record is about: the session’s active organization, or the organization listed.
role "owner" | "admin" | "member" required Role in the organization. Owners and admins invite, change roles and remove members; only owners grant or remove the owner role, and an organization always keeps one owner.
created_at string (date-time) required When the user was created.
sign_in_methods ("email" | "password" | "google" | "github" | "apple" | "microsoft" | "sso" | "passkey")[] required Every method the member has used to sign in to this organization, in the order first used. Empty until their first sign-in after this was recorded.
last_sign_in_method ("email" | "password" | "google" | "github" | "apple" | "microsoft" | "sso" | "passkey" | null) | null required How the member last signed in to this organization. null until their first sign-in after this was recorded.

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/organizations/members" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "members": [
    {
      "user_id": "usr_01k6x3j0rw0000n8w4yc0g3q5s",
      "email": "agent@machinemail.dev",
      "name": "Production",
      "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
      "role": "owner",
      "created_at": "2026-10-01T12:00:00.000Z",
      "sign_in_methods": ["email"],
      "last_sign_in_method": "email"
    }
  ]
}

Update Member

PATCH /v0/organizations/members/{user_id}

Change a member's role. The last owner cannot be demoted (409). Dashboard session only (the mm_session cookie): API keys and access tokens get 403. Owners and admins manage members; only owners grant, change or remove the owner role.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Path parameters

Field Type Description
user_id string required ID of the member (user_id).

Request body

Content type: application/json.

Field Type Description
role "owner" | "admin" | "member" required Role in the organization. Owners and admins invite, change roles and remove members; only owners grant or remove the owner role, and an organization always keeps one owner.

Response

200 The member (application/json)

Errors

Error bodies use the error envelope.

Example

curl -X PATCH "https://api.machinemail.dev/v0/organizations/members/usr_01k6x3j0rw0000n8w4yc0g3q5s" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "role": "owner"
}'
{
  "user_id": "usr_01k6x3j0rw0000n8w4yc0g3q5s",
  "email": "agent@machinemail.dev",
  "name": "Production",
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "role": "owner",
  "created_at": "2026-10-01T12:00:00.000Z",
  "sign_in_methods": ["email"],
  "last_sign_in_method": "email"
}

Remove Member

DELETE /v0/organizations/members/{user_id}

Remove a member, or leave the organization with your own user_id (any role). The last owner cannot leave or be removed (409).

Their access ends at once: their dashboard sessions and open event streams for this organization stop working, the API keys they created here are revoked (CLI keys, and keys minted with those keys, included), the apps they connected with OAuth (MCP clients) are disconnected, and invitations they sent that are still pending are revoked. Keys that record no creator (made before organizations had members) are not revoked: review them under API keys. Leaving moves your session to another organization you belong to whose sign-in policy your session meets (its single sign-on and sign-in method rules apply, as for switching); when there is none, the session ends and the mm_session cookie is cleared.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Path parameters

Field Type Description
user_id string required ID of the member (user_id).

Response

200 Removed (application/json)

Field Type Description
ok true required

Errors

Error bodies use the error envelope.

Example

curl -X DELETE "https://api.machinemail.dev/v0/organizations/members/usr_01k6x3j0rw0000n8w4yc0g3q5s" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "ok": true
}

Get Plan Usage

GET /v0/organizations/usage

The plan of the organization, its allowances and its usage in the current period: a calendar month in UTC, with the daily cap resetting at UTC midnight.

Inbound messages count once each; outbound messages count once per distinct recipient (to, cc and bcc). Spam and quarantined mail never count (mail your own receive lists block does). Storage includes drafts and held mail. Deleting mail frees storage but does not give back messages already counted.

On the Free plan, inbound mail past an allowance is held (held) and delivered when the allowance resets or after an upgrade; sends past it are refused with 402 plan_limit_exceeded. Paid plans are never blocked: usage past an allowance is billed as overage.

Organization-wide whatever the credential: Organization-scoped credentials only: pod and inbox credentials get 403.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: none beyond a valid key.

Response

200 Plan allowances and usage (application/json)

Field Type Description
plan "free" | "pro" | "team" | "scale" required Plan of the organization: free, pro, team or scale.
period object required
limits PlanLimits required The allowances that apply to the organization.
usage object required
held object required
enforcement "enforce" | "shadow" | "off" | "exempt" required enforce: limits apply. shadow and off: limits are not applied right now (usage is still counted). exempt: this organization has its own limits (unclaimed agent sandbox).

limits is a PlanLimits:

Field Type Description
messages_per_month integer | null required Inbound messages and outbound recipients together per calendar month (UTC). null: no combined cap (paid plans).
messages_per_day integer | null required The same, per UTC day. null: no daily cap.
inbound_per_month integer | null required Inbound messages included per month on paid plans (more is billed as overage). null on Free.
outbound_per_month integer | null required Outbound recipients included per month on paid plans (more is billed as overage). null on Free.
storage_bytes integer required Storage included, in bytes (1 GB = 1,000,000,000 bytes).
custom_domains integer required Custom domains included.
seats integer | null required Members (including pending invitations). null: unlimited.
overage boolean required true: usage past an allowance is billed, never blocked. false (Free): inbound past it is held and sending is refused until the reset.

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/organizations/usage" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "plan": "free",
  "period": {
    "start": "2026-10-01T12:00:00.000Z",
    "resets_at": "2026-10-01T12:00:00.000Z",
    "day_resets_at": "2026-10-01T12:00:00.000Z"
  },
  "limits": {
    "messages_per_month": 1,
    "messages_per_day": 1,
    "inbound_per_month": 1,
    "outbound_per_month": 1,
    "storage_bytes": 2048,
    "custom_domains": 1,
    "seats": 1,
    "overage": false
  },
  "usage": {
    "inbound": 1,
    "outbound": 1,
    "messages": 1,
    "messages_today": 1,
    "storage_bytes": 2048,
    "custom_domains": 1,
    "seats": 1
  },
  "held": {
    "count": 1,
    "bytes": 2048,
    "oldest_at": "2026-10-01T12:00:00.000Z"
  },
  "enforcement": "enforce"
}