Motor API

Motor's identity and billing layer: users, teams, members, keys, sessions, agents, usage, and invoices. The conventions of every Motor API are at https://new.motor.dev/docs.

Base URL https://new.motor.dev · version 2026-10-22 · OpenAPI 3.1 spec

Users

The person of a key.

GET /api/user

Get the user

Returns the user of the session key or the user key.

Responses

200The user.

FieldTypeDescription
created_atstring
emailstring

The email of the user's Google account.

idstring

The user's ID.

namestring

The user's name.

{
  "created_at": "2026-09-01T09:00:00.000Z",
  "email": "ada@example.com",
  "id": "user_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "Ada Lovelace"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

Teams

A team owns work, and its billing account pays for it. Each user can have a personal team. Every team has a card, so people make teams in the console, where they add the card.

GET /api/teams

List the teams

Returns the teams of the user, the personal team first; for an agent, its team. Needs team:read for an agent.

Responses

200The teams.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "card": {
        "brand": "visa",
        "exp_month": 12,
        "exp_year": 2030,
        "last4": "4242"
      },
      "created_at": "2026-10-01T09:00:00.000Z",
      "id": "team_1BbA6sXxyUWHYvKqN5T3dM",
      "name": "Lighthouse",
      "personal": false,
      "role": "admin",
      "spending_limit_cents": 50000,
      "standing": "active"
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

GET /api/teams/{team_id}

Get a team

Returns a team of the user, or the agent's team. Needs team:read for an agent.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Responses

200The team.

FieldTypeDescription
cardobject or null

The card that pays the team's invoices, or null.

created_atstring
idstring

The team's ID.

namestring

The team's handle.

personalboolean

Whether the team is a user's personal team, which gets $10 a month for free.

roleadmin | member | contributor

The caller's role: contributor for an agent.

spending_limit_centsinteger or null

The most that the team may spend in a month, or null for no limit.

standingactive | billing_required | over_limit | suspended

Whether the team may use the services now.

{
  "card": {
    "brand": "visa",
    "exp_month": 12,
    "exp_year": 2030,
    "last4": "4242"
  },
  "created_at": "2026-10-01T09:00:00.000Z",
  "id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "Lighthouse",
  "personal": false,
  "role": "admin",
  "spending_limit_cents": 50000,
  "standing": "active"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

PATCH /api/teams/{team_id}

Change a team

Changes a team's handle or spending limit. Only an admin can. A spending_limit_cents of null removes the limit.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Body fieldTypeDescription
namestring

The team's new handle.

spending_limit_centsinteger or null

The most that the team may spend in a month, in cents, or null for no limit.

Example request
{
  "spending_limit_cents": 50000
}
Responses

200The team.

FieldTypeDescription
cardobject or null

The card that pays the team's invoices, or null.

created_atstring
idstring

The team's ID.

namestring

The team's handle.

personalboolean

Whether the team is a user's personal team, which gets $10 a month for free.

roleadmin | member | contributor

The caller's role: contributor for an agent.

spending_limit_centsinteger or null

The most that the team may spend in a month, or null for no limit.

standingactive | billing_required | over_limit | suspended

Whether the team may use the services now.

{
  "card": {
    "brand": "visa",
    "exp_month": 12,
    "exp_year": 2030,
    "last4": "4242"
  },
  "created_at": "2026-10-01T09:00:00.000Z",
  "id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "Lighthouse",
  "personal": false,
  "role": "admin",
  "spending_limit_cents": 50000,
  "standing": "active"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

Members

The people of a team, and the invitations to join it.

GET /api/teams/{team_id}/invites

List the invitations

Returns the open invitations of a team.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Responses

200The invitations.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "created_at": "2026-10-22T09:00:00.000Z",
      "email": "grace@example.com",
      "expires_at": "2026-10-29T09:00:00.000Z",
      "id": "invite_1BbA6sXxyUWHYvKqN5T3dM",
      "role": "member",
      "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM"
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

POST /api/teams/{team_id}/invites

Invite someone

Emails an invitation to join the team, with a link that lasts 7 days. Only an admin can. An invitation to the same email replaces the last one.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Idempotency-Keyin headerstring

A key, 1 to 128 printable characters, that makes the request happen once: for 24 hours, the same key and request get the first answer again.

Body fieldTypeDescription
emailrequiredstring

Where the invitation goes.

roleadmin | member

The role in the team: member if you don't say.

Example request
{
  "email": "grace@example.com",
  "role": "member"
}
Responses

201The invitation.

FieldTypeDescription
created_atstring
emailstring

The email that Motor sent the invitation to.

expires_atstring
idstring

The invitation's ID.

roleadmin | member
team_idstring

The team's ID.

{
  "created_at": "2026-10-22T09:00:00.000Z",
  "email": "grace@example.com",
  "expires_at": "2026-10-29T09:00:00.000Z",
  "id": "invite_1BbA6sXxyUWHYvKqN5T3dM",
  "role": "member",
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

409The state of things doesn't allow the request, or an Idempotency-Key was used with another request.

{
  "error": {
    "code": "conflict",
    "message": "A team needs an admin. Make another member an admin first.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

DELETE /api/teams/{team_id}/invites/{invite_id}

Cancel an invitation

Cancels an invitation; its link stops working. Only an admin can.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

invite_idrequired in pathstring

The invitation's ID.

Responses

204Done. There is no body.

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

GET /api/teams/{team_id}/members

List the members

Returns the members of a team. Needs team:read for an agent.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Responses

200The members.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "joined_at": "2026-10-01T09:00:00.000Z",
      "role": "admin",
      "user": {
        "created_at": "2026-09-01T09:00:00.000Z",
        "email": "ada@example.com",
        "id": "user_1BbA6sXxyUWHYvKqN5T3dM",
        "name": "Ada Lovelace"
      }
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

PATCH /api/teams/{team_id}/members/{user_id}

Change a member's role

Makes a member an admin or a member. Only an admin can, and a team keeps at least one admin.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

user_idrequired in pathstring

The member's user ID.

Body fieldTypeDescription
rolerequiredadmin | member
Example request
{
  "role": "member"
}
Responses

200The member.

FieldTypeDescription
joined_atstring
roleadmin | member
userobject
{
  "joined_at": "2026-10-01T09:00:00.000Z",
  "role": "member",
  "user": {
    "created_at": "2026-09-01T09:00:00.000Z",
    "email": "ada@example.com",
    "id": "user_1BbA6sXxyUWHYvKqN5T3dM",
    "name": "Ada Lovelace"
  }
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

409The state of things doesn't allow the request, or an Idempotency-Key was used with another request.

{
  "error": {
    "code": "conflict",
    "message": "A team needs an admin. Make another member an admin first.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

DELETE /api/teams/{team_id}/members/{user_id}

Remove a member

Removes a member from a team: an admin can remove anyone, and a user can leave. The member's agents in the team are deregistered. Nobody can leave their personal team.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

user_idrequired in pathstring

The member's user ID.

Responses

204Done. There is no body.

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

409The state of things doesn't allow the request, or an Idempotency-Key was used with another request.

{
  "error": {
    "code": "conflict",
    "message": "A team needs an admin. Make another member an admin first.",
    "retryable": false
  }
}

Agents

Agents contribute to a team, with scopes, and with tokens that last at most 4 hours.

GET /api/agents

List the agents

Returns a team's agents, newest first: those with active registrations, or all of them.

ParameterTypeDescription
team_idrequired in querystring

The team's ID.

statusin queryrunning | all

running for active registrations (the default), or all to include deregistered and expired agents.

limitin queryinteger

The most items in the page, from 1 to 100. 50 if you don't say.

cursorin querystring

The next_cursor of the last page.

Responses

200The agents.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "created_at": "2026-10-22T09:00:00.000Z",
      "ended_at": null,
      "expires_at": "2026-10-23T09:00:00.000Z",
      "id": "agent_1BbA6sXxyUWHYvKqN5T3dM",
      "name": "reviewer",
      "parent_id": null,
      "scopes": [
        "current:*"
      ],
      "spending_limit_cents": 2000,
      "status": "running",
      "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
      "used_at": null,
      "user_id": "user_1BbA6sXxyUWHYvKqN5T3dM"
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

POST /api/agents

Register an agent

Registers an agent in a team and generates its first token. Motor shows the token once; it lasts at most 4 hours and can be renewed. Registration lasts 24 hours by default, up to 30 days. Renewing a token does not extend the registration. A session key registers an agent in a team of its user; an agent token with the scope agents:start registers a sub-agent in its own team, with scopes, a lifetime, and a spending limit no greater than its own. The team must have a card.

ParameterTypeDescription
Idempotency-Keyin headerstring

A key, 1 to 128 printable characters, that makes the request happen once: for 24 hours, the same key and request get the first answer again.

Body fieldTypeDescription
namerequiredstring

The agent's name, at most 100 characters.

scopesrequiredarray of string

What the agent may do, such as current:write, current:*, or *.

expires_ininteger

The agent's lifetime in seconds: 24 hours, or the parent's end, if you don't say.

spending_limit_centsinteger or null

The most that the agent may spend in a month, in cents.

team_idstring

The agent's team. A sub-agent is in its parent's team, so the field is optional for an agent token.

token_expires_ininteger

The first token's lifetime in seconds: 4 hours if you don't say.

Example request
{
  "name": "reviewer",
  "scopes": [
    "current:*"
  ],
  "spending_limit_cents": 2000,
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM"
}
Responses

201The agent, with `token`.

FieldTypeDescription
created_atstring
ended_atstring or null
expires_atstring

When the registration expires, unless the agent is deregistered sooner.

idstring

The agent's ID.

namestring

The agent's name.

parent_idstring or null

The agent that registered this one, or null.

scopesarray of string

What the agent may do (see the docs about scopes).

spending_limit_centsinteger or null

The most that the agent may spend in a month, or null for no limit of its own.

statusrunning | ended | expired
team_idstring

The agent's team.

used_atstring or null
user_idstring or null

The user who registered the agent's lineage.

tokenobject
{
  "created_at": "2026-10-22T09:00:00.000Z",
  "ended_at": null,
  "expires_at": "2026-10-23T09:00:00.000Z",
  "id": "agent_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "reviewer",
  "parent_id": null,
  "scopes": [
    "current:*"
  ],
  "spending_limit_cents": 2000,
  "status": "running",
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "token": {
    "expires_at": "2026-10-22T13:00:00.000Z",
    "id": "token_1BbA6sXxyUWHYvKqN5T3dM",
    "token": "motor_tk_9fJ2kL3mN4pQ5rS6tU7vW8xY9zA0bC1d"
  },
  "used_at": null,
  "user_id": "user_1BbA6sXxyUWHYvKqN5T3dM"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

402The team needs a card before it can do billable work.

{
  "error": {
    "code": "billing_required",
    "message": "The team needs a card before it can do billable work.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

409The state of things doesn't allow the request, or an Idempotency-Key was used with another request.

{
  "error": {
    "code": "conflict",
    "message": "A team needs an admin. Make another member an admin first.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

GET /api/agents/{agent_id}

Get an agent

Returns an agent: one of the user's teams, the agent itself, or one of its descendants.

ParameterTypeDescription
agent_idrequired in pathstring

The agent's ID.

Responses

200The agent.

FieldTypeDescription
created_atstring
ended_atstring or null
expires_atstring

When the registration expires, unless the agent is deregistered sooner.

idstring

The agent's ID.

namestring

The agent's name.

parent_idstring or null

The agent that registered this one, or null.

scopesarray of string

What the agent may do (see the docs about scopes).

spending_limit_centsinteger or null

The most that the agent may spend in a month, or null for no limit of its own.

statusrunning | ended | expired
team_idstring

The agent's team.

used_atstring or null
user_idstring or null

The user who registered the agent's lineage.

tokenobject
{
  "created_at": "2026-10-22T09:00:00.000Z",
  "ended_at": null,
  "expires_at": "2026-10-23T09:00:00.000Z",
  "id": "agent_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "reviewer",
  "parent_id": null,
  "scopes": [
    "current:*"
  ],
  "spending_limit_cents": 2000,
  "status": "running",
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "used_at": null,
  "user_id": "user_1BbA6sXxyUWHYvKqN5T3dM"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

DELETE /api/agents/{agent_id}

Deregister an agent

Deregisters an agent and its sub-agents, and revokes their tokens. An agent can deregister itself and its descendants; a user, the agents that they registered; an admin, any agent of the team.

ParameterTypeDescription
agent_idrequired in pathstring

The agent's ID.

Responses

200The agent.

FieldTypeDescription
created_atstring
ended_atstring or null
expires_atstring

When the registration expires, unless the agent is deregistered sooner.

idstring

The agent's ID.

namestring

The agent's name.

parent_idstring or null

The agent that registered this one, or null.

scopesarray of string

What the agent may do (see the docs about scopes).

spending_limit_centsinteger or null

The most that the agent may spend in a month, or null for no limit of its own.

statusrunning | ended | expired
team_idstring

The agent's team.

used_atstring or null
user_idstring or null

The user who registered the agent's lineage.

tokenobject
{
  "created_at": "2026-10-22T09:00:00.000Z",
  "ended_at": "2026-10-22T10:00:00.000Z",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "id": "agent_1BbA6sXxyUWHYvKqN5T3dM",
  "name": "reviewer",
  "parent_id": null,
  "scopes": [
    "current:*"
  ],
  "spending_limit_cents": 2000,
  "status": "ended",
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "used_at": null,
  "user_id": "user_1BbA6sXxyUWHYvKqN5T3dM"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

POST /api/agents/{agent_id}/tokens

Renew an agent's token

Gives a registered agent a new token, which lasts at most 4 hours, without extending its registration. Previous tokens keep working until they expire. A session key of the user who registered the agent, or of a team admin, can; so can an ancestor agent with agents:start. An agent can't renew its own token.

ParameterTypeDescription
agent_idrequired in pathstring

The agent's ID.

Idempotency-Keyin headerstring

A key, 1 to 128 printable characters, that makes the request happen once: for 24 hours, the same key and request get the first answer again.

Body fieldTypeDescription
expires_ininteger

The token's lifetime in seconds: 4 hours if you don't say.

Example request
{}
Responses

201The token.

FieldTypeDescription
expires_atstring

When the token expires: at most 4 hours after it's made, and no later than the agent's registration expiry.

idstring

The token's ID.

tokenstring

The token itself (motor_tk_…). Motor shows it once.

{
  "expires_at": "2026-10-22T13:00:00.000Z",
  "id": "token_1BbA6sXxyUWHYvKqN5T3dM",
  "token": "motor_tk_9fJ2kL3mN4pQ5rS6tU7vW8xY9zA0bC1d"
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

409The state of things doesn't allow the request, or an Idempotency-Key was used with another request.

{
  "error": {
    "code": "conflict",
    "message": "A team needs an admin. Make another member an admin first.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

Sessions

Session keys last 24 hours. motor auth gets one with the person's approval in the browser; a user key mints one.

GET /api/sessions

List the session keys

Returns the user's session keys that work now.

Responses

200The session keys.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "bound": true,
      "created_at": "2026-10-22T09:00:00.000Z",
      "created_via": "browser",
      "expires_at": "2026-10-23T09:00:00.000Z",
      "hint": "motor_sk_…a1B2",
      "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
      "kind": "session",
      "name": "motor on ada-macbook",
      "revoked_at": null,
      "status": "active",
      "used_at": null
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

POST /api/sessions

Mint a session key

Mints a session key, which lasts 24 hours, with a user key, such as in CI. A DPoP header with a proof binds the session key to the proof's key.

ParameterTypeDescription
Idempotency-Keyin headerstring

A key, 1 to 128 printable characters, that makes the request happen once: for 24 hours, the same key and request get the first answer again.

Body fieldTypeDescription
namestring

A name for the session: the user key's name if you don't say.

Example request
{
  "name": "CI run"
}
Responses

201The session key, with `token`.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": false,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "api",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_sk_…a1B2",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "session",
  "name": "CI run",
  "revoked_at": null,
  "status": "active",
  "token": "motor_sk_9fJ2kL3mN4pQ5rS6tU7vW8xY9zA0bC1d",
  "used_at": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

POST /api/sessions/device_authorizations

no credential

Start a device sign-in

Starts the sign-in of a computer without a browser (RFC 8628), which motor auth --device uses. The person types user_code at verification_uri and approves with a passkey; meanwhile, the CLI polls exchange_session with device_code. A DPoP header names the device key that the session key will be bound to. Each address may make 30 of these requests a minute.

Body fieldTypeDescription
client_namestring

A name for the computer, such as motor on build-server.

Example request
{
  "client_name": "motor on build-server"
}
Responses

201The codes.

FieldTypeDescription
device_codestring

The secret that the CLI polls with.

expires_ininteger

Seconds until the codes expire.

intervalinteger

The least seconds between two polls.

user_codestring

The code that the person types, such as WDJB-MJHT.

verification_uristring

Where the person types the code.

verification_uri_completestring

The same page, with the code.

{
  "device_code": "Kq3mN4pQ5rS6tU7vW8xY9zA0bC1d2E3f",
  "expires_in": 600,
  "interval": 5,
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://new.motor.dev/activate",
  "verification_uri_complete": "https://new.motor.dev/activate?user_code=WDJB-MJHT"
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

429The credential made more than 600 requests in a minute.

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests: the limit is 600 a minute.",
    "retryable": true
  }
}

POST /api/sessions/exchange

no credential

Get the session key of a sign-in

Trades the code of a browser sign-in, with its PKCE verifier, or an approved device code, for a session key. A DPoP header binds the session key to the proof's key; the key must be the one that the sign-in named. Until the person approves a device code, the answer is authorization_pending, or slow_down for a poll that comes too soon.

Body fieldTypeDescription
grant_typerequiredauthorization_code | device_code
codestring

The code of a browser sign-in.

code_verifierstring

The PKCE verifier of the code's challenge.

device_codestring

The device code of a device sign-in.

redirect_uristring

The loopback URL of the browser sign-in.

Example request
{
  "device_code": "Kq3mN4pQ5rS6tU7vW8xY9zA0bC1d2E3f",
  "grant_type": "device_code"
}
Responses

201The session key, with `token`.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": true,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "browser",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_sk_…a1B2",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "session",
  "name": "motor on ada-macbook",
  "revoked_at": null,
  "status": "active",
  "token": "motor_sk_9fJ2kL3mN4pQ5rS6tU7vW8xY9zA0bC1d",
  "used_at": null
}

400The body isn't a JSON object, or the request can't go on.

{
  "error": {
    "code": "invalid_json",
    "message": "The body isn't a JSON object: unexpected EOF.",
    "retryable": false
  }
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}

429The credential made more than 600 requests in a minute.

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests: the limit is 600 a minute.",
    "retryable": true
  }
}

GET /api/sessions/{session_id}

Get a session key

Returns one of the user's session keys.

ParameterTypeDescription
session_idrequired in pathstring

The session key's ID.

Responses

200The session key.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": true,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "browser",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_sk_…a1B2",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "session",
  "name": "motor on ada-macbook",
  "revoked_at": null,
  "status": "active",
  "used_at": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

DELETE /api/sessions/{session_id}

Revoke a session key

Revokes a session key, and deregisters its agents. A session key can revoke itself, which is how the CLI signs out; a user key can revoke any of its user's session keys.

ParameterTypeDescription
session_idrequired in pathstring

The session key's ID.

Responses

200The session key.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": true,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "browser",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_sk_…a1B2",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "session",
  "name": "motor on ada-macbook",
  "revoked_at": "2026-10-22T10:00:00.000Z",
  "status": "revoked",
  "used_at": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

Keys

User keys last until they expire, for automation. Only a user key manages them.

GET /api/keys

List the user keys

Returns the user's user keys. Only a user key can.

Responses

200The keys.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "bound": false,
      "created_at": "2026-10-22T09:00:00.000Z",
      "created_via": "console",
      "expires_at": "2027-01-20T09:00:00.000Z",
      "hint": "motor_uk_…z9Y8",
      "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
      "kind": "user",
      "name": "CI",
      "revoked_at": null,
      "status": "active",
      "used_at": null
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

GET /api/keys/{key_id}

Get a user key

Returns one of the user's user keys. Only a user key can.

ParameterTypeDescription
key_idrequired in pathstring

The key's ID.

Responses

200The key.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": false,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "console",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_uk_…z9Y8",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "user",
  "name": "CI",
  "revoked_at": null,
  "status": "active",
  "used_at": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

DELETE /api/keys/{key_id}

Revoke a user key

Revokes a user key, and the session keys that it minted. Their agents are deregistered. Only a user key can.

ParameterTypeDescription
key_idrequired in pathstring

The key's ID.

Responses

200The key.

FieldTypeDescription
boundboolean

Whether the key is bound to a device key, and needs a DPoP proof with each request.

created_atstring
created_viaconsole | browser | device | api

How the key came to be.

expires_atstring or null

When the key expires, or null for a user key that never does.

hintstring

The key, with all but its last 4 characters hidden.

idstring

The key's ID.

kinduser | session

A user key or a session key.

namestring

The key's name: for a session key, the computer that asked for it.

revoked_atstring or null
statusactive | expired | revoked
used_atstring or null
tokenstring

The key itself. Only the response that makes the key has it; Motor shows it once.

{
  "bound": false,
  "created_at": "2026-10-22T09:00:00.000Z",
  "created_via": "console",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "hint": "motor_uk_…z9Y8",
  "id": "key_1BbA6sXxyUWHYvKqN5T3dM",
  "kind": "user",
  "name": "CI",
  "revoked_at": "2026-10-22T10:00:00.000Z",
  "status": "revoked",
  "used_at": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

Billing

What a team used, and its invoices.

GET /api/teams/{team_id}/invoices

List the invoices

Returns the team's invoices, newest first.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

Responses

200The invoices.

FieldTypeDescription
dataarray of object
next_cursorstring or null

The cursor of the next page, or null on the last page.

{
  "data": [
    {
      "allowance_cents": 0,
      "created_at": "2026-10-01T03:00:00.000Z",
      "credit_cents": 0,
      "hosted_url": "https://invoice.stripe.com/i/acct_x/in_x",
      "id": "invoice_1BbA6sXxyUWHYvKqN5T3dM",
      "month": "2026-09",
      "paid_at": "2026-10-01T04:00:00.000Z",
      "status": "paid",
      "subtotal_cents": 1840,
      "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
      "total_cents": 1840
    }
  ],
  "next_cursor": null
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

GET /api/teams/{team_id}/usage

Get the usage

Returns what the team used in a month, by meter, and what it costs. Needs usage:read for an agent.

ParameterTypeDescription
team_idrequired in pathstring

The team's ID.

monthin querystring

The month, such as 2026-10. The current month if you don't say.

Responses

200The usage.

FieldTypeDescription
allowance_centsinteger

The free allocation of a personal team.

credit_centsinteger
linesarray of object
monthstring

The month, such as 2026-10.

subtotal_centsinteger
team_idstring

The team's ID.

total_centsinteger

What the team owes for the month, so far for the current month.

{
  "allowance_cents": 0,
  "credit_cents": 0,
  "lines": [
    {
      "amount_cents": 13,
      "meter": "bytes_in",
      "priced_quantity": "2.500000",
      "priced_unit": "GB",
      "quantity": "2500000000",
      "unit": "bytes"
    }
  ],
  "month": "2026-10",
  "subtotal_cents": 13,
  "team_id": "team_1BbA6sXxyUWHYvKqN5T3dM",
  "total_cents": 13
}

401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.

{
  "error": {
    "code": "unauthorized",
    "message": "The credential is unknown, revoked, or expired.",
    "retryable": false
  }
}

403The credential can't do this.

{
  "error": {
    "code": "forbidden",
    "message": "Your credential can't do this.",
    "retryable": false
  }
}

404There is no such resource, or the credential can't see it.

{
  "error": {
    "code": "not_found",
    "message": "There is no such resource, or you can't see it.",
    "retryable": false
  }
}

422A field or a parameter has a value that Motor can't accept.

{
  "error": {
    "code": "invalid_field",
    "message": "`name` is required.",
    "retryable": false
  }
}