Accounts and Members

Published

Updated

Accounts are the top-level API boundary. Environments, VMs, tasks, users, invitations, secrets, snapshots, and logs all live under an account.

Most integrations start by discovering the account ID, then using account-scoped routes for the rest of their work.

Create an Account

POST /v1/accounts makes you the owner of the new account. If you already belong to an active account, the new account starts active and is usable immediately. Otherwise it starts pending and awaits activation, including when your existing accounts are paused or rejected. Check activation_state in the response before using account-scoped routes.

Discover Accounts

curl -s "$WALLFACER_API/accounts" \
  -H "Authorization: Bearer $WALLFACER_TOKEN" \
  | jq ".data[] | {id, name}"

Store the chosen account ID. It appears in most routes:

/v1/accounts/{account_id}/...

Account responses from GET /v1/accounts, GET /v1/accounts/{account_id}, account updates, and sign-in include agent_credentials_enabled. This read-only boolean tells clients whether the account allows agents to use their own model API keys and subscription tokens. It is not an account setting you can change with PATCH; sending it in an account update does not enable the feature. See Model Keys for the app behavior.

Set an Account Palette

Account owners and admins can set a palette for the whole account with PATCH /v1/accounts/{account_id}. Every member can read the effective palette in account responses, including GET /v1/accounts and GET /v1/accounts/{account_id}. Set the palette through the API:

curl -X PATCH "$WALLFACER_API/accounts/$ACCOUNT_ID" \
  -H "Authorization: Bearer $WALLFACER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"palette":"evergreen"}'

Choose evergreen, ink-parchment, slate-lilac, or copper-cream. Send {"palette":null} to clear the selection; the account then reads as ink-parchment. Omit palette from a PATCH to leave the selection unchanged. Members can read the palette but cannot change it.

The palette is shared across the account. Your personal light or dark appearance is a separate preference stored on each device. Clients should recognize a palette by its full value or the family before / in a variant such as ink-parchment/dim, and use ink-parchment for an unknown value.

Resolve Members

Account user routes are useful for automation that needs to map an external identity to a Wallfacer user. The most common case is resolving a GitHub username before creating a task on that user's behalf.

curl -s "$WALLFACER_API/accounts/$ACCOUNT_ID/users?github_username=$GITHUB_LOGIN" \
  -H "Authorization: Bearer $WALLFACER_TOKEN" \
  | jq ".data[0] // null"

An empty data array means no active account member matched that GitHub username. Treat that as a skip, not as an API failure.

Agents

An agent is an AI identity in the account that runs work. Every task runs as an agent, and the commits, pull requests, and credentials that task uses resolve to it. The responsible human is recorded separately as the task owner.

Creating an agent is an admin operation. When you create one without naming an environment_id, Wallfacer provisions a computer for it, an account-editable environment named after the agent, and sets it as the agent's environment. The agent is runnable the moment it exists. The computer starts as a default Linux box with no repositories and begins generating its base snapshot right away; add repositories or services to it later and the snapshot regenerates.

A task defaults its environment_id from its agent. A task that names an agent and omits environment_id lands on that agent's computer without you naming the environment. See Tasks and Sessions for the create call.

Connect GitHub to an agent only when it will work on code in a GitHub repository. An agent whose computer has no repositories runs with no GitHub connected at all.

Call Voice

Set an agent's call voice with PATCH /v1/accounts/{account_id}/agents/{agent_user_id} and the voice field. The agent's GET response reports the selection. Accepted values are alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, and cedar. Send null to use the default voice.

Standing State

Each agent carries objectives and todos under /v1/accounts/{account_id}/agents/{agent_user_id}.

  • objectives is readable, creatable, editable, and closable by any account member. Closing is a PATCH carrying both status: "closed" and an outcome (done, dropped, or superseded) rather than a verb segment on the URL. The two are validated against each other: an outcome without status: "closed", or status: "closed" without an outcome, is a 422.
  • todos is read-only and filters by status, ref, and objective_id. There is no write endpoint by design: the agent writes its own todos as it commits to them.

See Agents for what the two are for.

Mail Policy

The agent's mail_policy is read on GET and replaced wholesale on PATCH of the agent. A partial policy is a 422. See Email an Agent for the fields and the defaults.

People

/v1/accounts/{account_id}/people is the account's directory: members, agents, and identifiable people your agents have met on a channel, each with the spellings that resolve to them. A voice call without caller identity remains in the event stream and does not create a person in this list.

  • GET /people and GET /people/{person_id} read the record.
  • PATCH /people/{person_id} sets the preferred channel and the contact notes your agents read.
  • POST /people/{person_id}/merges folds a duplicate into this person. Two rows that are both account members cannot be merged, and a member row can only be the survivor.

These routes are open to any account member. See Accounts for the app surface.

Slack Workspace Connection

GET /v1/accounts/{account_id}/connections/slack returns the account's Slack connection, including workspace_domain as a bare host such as acme.slack.com. The field is null until the first agent app is installed. Without a Slack connection, the endpoint returns 404. See Agents in Slack for setup.

The Keychain

Credentials your agents use to sign into third-party services are account-owned and granted per agent.

GoalRoute
List or store a credentialGET and POST /v1/accounts/{account_id}/credentials
Read, replace, or delete oneGET, PATCH, DELETE /v1/accounts/{account_id}/credentials/{credential_id}
See who holds itGET /v1/accounts/{account_id}/credentials/{credential_id}/grants
Grant or revoke for one agentPUT and DELETE /v1/accounts/{account_id}/credentials/{credential_id}/grants/{agent}
List what one agent holdsGET /v1/accounts/{account_id}/agents/{agent_user_id}/credentials

No route returns a stored value. Responses carry the name, the reference the agent reaches it by, the kind, grant dates, and how the credential is audited. See The Account Keychain for what an agent does with one.

Credential Requests

Agents can ask for an account keychain credential they do not hold. GET /v1/accounts/{account_id}/credential-requests lists requests, newest first; filter by status (pending, resolved, or expired) or session_id. GET /v1/accounts/{account_id}/credential-requests/{credentialRequest_id} reads one request, including its requested name, agent, reason, status, deadline, and can_resolve flag.

Read replacement and replaces_credential_id before answering. For replacement: false, find an existing account credential whose reference matches the request and grant it to the requesting agent. If its kind differs from the requested kind, warn the user and confirm it is the intended credential before granting. If no matching reference exists, create a credential with the request's name and kind and a supplied value, then grant it. For replacement: true, replace the value of the existing replaces_credential_id credential, keeping its ID and grants. Send POST /v1/accounts/{account_id}/credential-requests/{credentialRequest_id}/resolve with the matching credential's UUID as credential_id. Only a person with edit access to the request's computer can resolve it. Resolution checks the matching credential's reference and agent grant and, for a replacement, also verifies that the value changed after the request; it does not create or grant a credential. An unchanged replacement returns credential_not_replaced. Requests expire after 24 hours. Repeating resolution with the same credential is safe and notifies the agent once. See The Account Keychain for the task flow and the API Reference for exact fields and errors.

Roles

Account members have one of three roles:

RoleMeaning
ownerFull control, including ownership and other owners.
adminCan add, update, and remove members, but cannot grant or modify owner.
memberCan use the account but cannot manage membership.

Admin-level operations include attaching existing users, updating roles, removing users, and managing invitations. Owner-specific constraints still apply: only owners can remove owners, and the last owner cannot be removed.

Invitations

Invitations are for emails that do not yet belong to a Wallfacer user. When accepted, the invitee joins the account with the invited role.

There are two invitation flows:

  • Account admins list and create invitations under /v1/accounts/{account}/invitations.
  • Invitees use public token routes under /v1/invitations/{token} to inspect and accept the invitation.

The public show-by-token route reveals enough metadata to identify the account and inviter, but the token itself is the secret. Do not log invitation URLs.

Task Ownership and Execution Identity

Every task has two distinct identities: the agent it runs as, and the human accountable for it.

  • Execution identity (created_by). The agent the task runs as. Every commit, pull request, and credential resolves to this agent. It is always an agent, never a person. On task creation, created_by is optional and must be an enabled agent of the account; omit it to use the account's connected agent (the default).
  • Owner (owner_user_id). The human accountable for the task. When a person's token creates a task, that person becomes the owner. A task an agent opens on its own stays unowned and surfaces in a shared "needs someone" queue rather than routing to anyone.
{
  "title": "Fix the assigned issue",
  "prompt": "Resolve the attached ticket.",
  "environment_id": "019d8e44-e110-71f6-864b-8e91470dcc4a"
}

Task access is account-scoped, not restricted to the creator: any member of the account can list and read the account's tasks. Filter by execution identity with the created_by query parameter, or by responsible human with owner_user_id.

Environment Visibility

Environment visibility also affects account members:

  • private environments are only visible and usable by their creator.
  • account_read lets members use the environment but not edit it.
  • account_edit lets members use, edit, and delete it.

Use account_read for shared team environments that should be stable. Use account_edit only when account members should be able to change the manifest and regenerate snapshots.