ConnectionsService
Connect an account on behalf of one of your users, read the state of one, and disconnect it. Your code never sees a credential: it starts a flow, sends the person to the address that comes back, and afterwards holds an account id.
Every call is a POST to https://api.atmon.ai/automaton.v1.ConnectionsService/<Call> with a JSON body, and authenticates with Authorization: Bearer <your project key>. Field names in JSON are lowerCamelCase, so the field written tool_slug below is toolSlug on the wire. How to call the API has the whole convention.
Calls
| Call | Request | Response | Summary |
|---|---|---|---|
InitiateConnection | InitiateConnectionRequest | InitiateConnectionResponse | Starts an auth flow for one entity and one toolkit. |
SubmitAPIKey | SubmitAPIKeyRequest | SubmitAPIKeyResponse | Completes an api_key connection. |
SubmitBasicAuth | SubmitBasicAuthRequest | SubmitBasicAuthResponse | Completes a basic connection. |
GetConnectedAccount | GetConnectedAccountRequest | GetConnectedAccountResponse | Reads one connected account's status and granted scopes. |
ListConnectedAccounts | ListConnectedAccountsRequest | ListConnectedAccountsResponse | Lists an entity's connected accounts, optionally for one toolkit. |
RevokeConnectedAccount | RevokeConnectedAccountRequest | RevokeConnectedAccountResponse | Revokes an account: the stored credential is dropped and the provider's revocation endpoint is called where the toolkit declares one. |
UpdateAccountVariables | UpdateAccountVariablesRequest | UpdateAccountVariablesResponse | Corrects an account's account_variables in place, so a typo in a subdomain is an edit rather than a reconnection. |
InitiateConnection
Starts an auth flow for one entity and one toolkit. For an OAuth toolkit it answers the authorization URL to send the end user to; the account stays PENDING until the flow completes, and the flow expires after ten minutes. The project's scope caps are enforced here, before a consent URL exists, because an approved scope is a real grant whatever happens afterward.
Request InitiateConnectionRequest, response InitiateConnectionResponse.
POST /automaton.v1.ConnectionsService/InitiateConnection HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"entityId": "...",
"toolkitSlug": "...",
"requestedScopes": ["..."],
"redirectUri": "...",
"credentialKind": "...",
"accountVariables": {"...": "..."},
"authScheme": "..."
}
The response:
{
"connectedAccountId": "...",
"authorizationUrl": "..."
}
SubmitAPIKey
Completes an api_key connection. It is the only RPC that carries a raw credential, and it carries it one way: the account goes ACTIVE and the key is readable by nothing afterwards.
Request SubmitAPIKeyRequest, response SubmitAPIKeyResponse.
POST /automaton.v1.ConnectionsService/SubmitAPIKey HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"connectedAccountId": "...",
"apiKey": "..."
}
The response:
{}
SubmitBasicAuth
Completes a basic connection. It carries the two halves of an HTTP basic credential the same way SubmitAPIKey carries one key: one way, into the vault, and the account goes ACTIVE.
Request SubmitBasicAuthRequest, response SubmitBasicAuthResponse.
POST /automaton.v1.ConnectionsService/SubmitBasicAuth HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"connectedAccountId": "...",
"username": "...",
"password": "..."
}
The response:
{}
GetConnectedAccount
Reads one connected account's status and granted scopes. No method on this service ever returns credential material.
Request GetConnectedAccountRequest, response GetConnectedAccountResponse.
POST /automaton.v1.ConnectionsService/GetConnectedAccount HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"id": "..."
}
The response:
{
"connectedAccount": {
"id": "...",
"entityId": "...",
"toolkitSlug": "...",
"status": "CONNECTION_STATUS_PENDING",
"grantedScopes": ["..."],
"createdAt": "2026-01-31T09:15:00Z",
"credentialKind": "...",
"accountVariables": {"...": "..."},
"authScheme": "..."
}
}
ListConnectedAccounts
Lists an entity's connected accounts, optionally for one toolkit. This is how to tell in advance whether a call would answer not_connected.
Request ListConnectedAccountsRequest, response ListConnectedAccountsResponse.
POST /automaton.v1.ConnectionsService/ListConnectedAccounts HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"entityId": "...",
"toolkitSlug": "..."
}
The response:
{
"connectedAccounts": [{
"id": "...",
"entityId": "...",
"toolkitSlug": "...",
"status": "CONNECTION_STATUS_PENDING",
"grantedScopes": ["..."],
"createdAt": "2026-01-31T09:15:00Z",
"credentialKind": "...",
"accountVariables": {"...": "..."},
"authScheme": "..."
}]
}
RevokeConnectedAccount
Revokes an account: the stored credential is dropped and the provider's revocation endpoint is called where the toolkit declares one. A provider that refuses the revocation is logged, not surfaced; the account is revoked locally either way.
Request RevokeConnectedAccountRequest, response RevokeConnectedAccountResponse.
POST /automaton.v1.ConnectionsService/RevokeConnectedAccount HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"id": "..."
}
The response:
{}
UpdateAccountVariables
Corrects an account's account_variables in place, so a typo in a subdomain is an edit rather than a reconnection. It changes where this account's calls go, never what its credential is, and it refuses a variable that decides the dialled origin: that value chose the server the account's credential is presented to, and moving it afterwards would present a live credential to a server the provider never issued it for. Changing the origin is a new connection.
Request UpdateAccountVariablesRequest, response UpdateAccountVariablesResponse.
POST /automaton.v1.ConnectionsService/UpdateAccountVariables HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"connectedAccountId": "...",
"accountVariables": {"...": "..."}
}
The response:
{
"connectedAccount": {
"id": "...",
"entityId": "...",
"toolkitSlug": "...",
"status": "CONNECTION_STATUS_PENDING",
"grantedScopes": ["..."],
"createdAt": "2026-01-31T09:15:00Z",
"credentialKind": "...",
"accountVariables": {"...": "..."},
"authScheme": "..."
}
}
Messages
ConnectedAccount
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 | |
entity_id | string | 2 | |
toolkit_slug | string | 3 | |
status | ConnectionStatus | 4 | |
granted_scopes | repeated string | 5 | |
created_at | google.protobuf.Timestamp | 6 | |
credential_kind | string | 7 | credential_kind is set instead of toolkit_slug when the account holds a credential for something that is not a catalog toolkit, such as a model provider. Exactly one of the two is ever set. |
account_variables | map<string, string> | 8 | account_variables are the per-customer parts of the toolkit's base_url this account answered: a subdomain, an application id, a cluster address. They are not secret, which is why they come back on a read: they say where this account's calls go, never what the credential is. |
auth_scheme | string | 9 | auth_scheme is the toolkit auth scheme this account was created under ("oauth2", "api_key", or "basic"), which is fixed for its life: the vault holds one credential of that shape. Connecting the same toolkit under another scheme is another account. No account is ever created under "client_credentials": that credential belongs to the project, so there is nothing per-entity to connect. |
GetConnectedAccountRequest
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 |
GetConnectedAccountResponse
| Field | Type | # | Notes |
|---|---|---|---|
connected_account | ConnectedAccount | 1 |
InitiateConnectionRequest
| Field | Type | # | Notes |
|---|---|---|---|
entity_id | string | 1 | |
toolkit_slug | string | 2 | |
requested_scopes | repeated string | 3 | empty requests the toolkit default |
redirect_uri | string | 4 | where the end user lands after consent |
credential_kind | string | 5 | credential_kind names a non-catalog credential subject, from a closed set the server registers (model_provider:openai, model_provider:anthropic). It is mutually exclusive with toolkit_slug, takes the api_key path only, and accepts neither scopes nor a redirect: there is no provider app to consent to and no end user to send anywhere. An unregistered kind is refused. |
account_variables | map<string, string> | 6 | account_variables answers the toolkit's account_variables block, keyed by declared name. Every variable the toolkit declares must be present and no other name may be: a missing one would leave a placeholder in the host of every call, and an extra one would sit on the account unused. |
auth_scheme | string | 7 | auth_scheme names which of the toolkit's declared auth schemes to connect under, by type ("oauth2", "api_key", or "basic"). Empty takes the toolkit's default, which is the first scheme its catalog entry declares that this deployment can run and that an entity can connect under. A scheme the toolkit does not declare is refused rather than substituted, and the account records what it was created under. "client_credentials" is refused here: the project holds that credential, so a call under it needs no account. |
InitiateConnectionResponse
| Field | Type | # | Notes |
|---|---|---|---|
connected_account_id | string | 1 | status PENDING until the flow completes |
authorization_url | string | 2 | send the end user here for OAuth toolkits |
ListConnectedAccountsRequest
| Field | Type | # | Notes |
|---|---|---|---|
entity_id | string | 1 | |
toolkit_slug | string | 2 | empty lists all toolkits for the entity |
ListConnectedAccountsResponse
| Field | Type | # | Notes |
|---|---|---|---|
connected_accounts | repeated ConnectedAccount | 1 |
RevokeConnectedAccountRequest
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 |
RevokeConnectedAccountResponse
No fields. The call takes its scope from the authenticated project.
SubmitAPIKeyRequest
| Field | Type | # | Notes |
|---|---|---|---|
connected_account_id | string | 1 | connected_account_id is a PENDING account InitiateConnection returned under the api_key scheme, either for an api_key toolkit or for a credential kind. |
api_key | string | 2 | api_key is the raw credential. It is write-only in the strict sense: it is sealed into the vault on arrival, no read on this service or any other ever returns it, and it is never written to a log line or a trace. Send it over TLS; a request that carries it should not be recorded by a proxy. |
SubmitAPIKeyResponse
No fields. The call takes its scope from the authenticated project.
SubmitBasicAuthRequest
| Field | Type | # | Notes |
|---|---|---|---|
connected_account_id | string | 1 | connected_account_id is a PENDING account InitiateConnection returned under the basic scheme. |
username | string | 2 | username and password are the two halves of the HTTP basic credential, and both are write-only in the same strict sense as api_key above: sealed into the vault on arrival, returned by no read, written to no log line and no trace. An empty password is accepted, because providers that carry the whole secret in the username half are common. A username holding a colon is refused: RFC 7617 splits the pair on the first colon, so the provider would read a different pair from the one sent. |
password | string | 3 |
SubmitBasicAuthResponse
No fields. The call takes its scope from the authenticated project.
UpdateAccountVariablesRequest
UpdateAccountVariablesRequest corrects the per-customer parts of an existing account's address. A mistyped subdomain otherwise costs a revoke and a reconnect, which for an OAuth account means sending the end user through consent again over a typo.
| Field | Type | # | Notes |
|---|---|---|---|
connected_account_id | string | 1 | |
account_variables | map<string, string> | 2 | account_variables replaces the whole set, keyed by declared name, under the same rule InitiateConnection applies: every variable the toolkit declares must be present and no other name may be. A merge would let a caller send one name and leave the account holding a value nobody has looked at since it was first typed. |
UpdateAccountVariablesResponse
| Field | Type | # | Notes |
|---|---|---|---|
connected_account | ConnectedAccount | 1 |
Enums
ConnectionStatus
| Value | # | Meaning |
|---|---|---|
CONNECTION_STATUS_UNSPECIFIED | 0 | |
CONNECTION_STATUS_PENDING | 1 | auth flow started, not completed |
CONNECTION_STATUS_ACTIVE | 2 | |
CONNECTION_STATUS_EXPIRED | 3 | refresh failed, re-auth required |
CONNECTION_STATUS_REVOKED | 4 |