Credentials
12 calls. Every request needs the Authorization header: see the overview.
credentials.deleteByTag
Section titled “credentials.deleteByTag”DELETE /credentialsDeletes every credential with this tag (and takes them out of their stacks), and returns how many it deleted.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
tag | string | yes |
Response: integer (200)
curl -X DELETE "https://api.maitento.com/credentials" \ -H "Authorization: $MAITENTO_AUTH"const deleted = await mt.credentials.deleteByTag("customer-42");mt.credentials.delete_by_tag("acme")credentials.list
Section titled “credentials.list”GET /credentialsEvery credential of the tenant, by name; with tag, only those with that tag.
Who can call it: Admins and members, with an API key or a portal session. Try it in the API playground.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
tag | string |
Response: ModelCredential[] (200)
curl -X GET "https://api.maitento.com/credentials" \ -H "Authorization: $MAITENTO_AUTH"const credentials = await mt.credentials.list({ tag: "customer-42" });mt.credentials.list(tag="acme")credentials.create
Section titled “credentials.create”POST /credentialsCreates an API-key credential and returns it, with its id. Refused with ValidationError when the name is taken, a key or the endpoint is invalid, or the plan’s credential limit is reached.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Request body: ModelCredentialRequest
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ||
description | string | null | ||
provider | ModelKeyProvider | ||
endpoint | string | null | An HTTPS endpoint on the public internet; null for the provider’s public API. | |
cloud | CredentialCloudInput| null | For an Anthropic credential: Claude on Amazon Bedrock (with awsRegion) or Google Vertex AI (with gcpProjectId and gcpRegion), with no endpoint. The key is then the Bedrock API key, or the service account’s JSON key file. Only code pipelines’ Claude Code agents run on it. | |
keys | ModelCredentialKeyRequest[] | ||
models | CredentialModelInput[] | ||
tag | string | null |
Response: ModelCredential (200)
curl -X POST "https://api.maitento.com/credentials" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"name":"...","description":"...","provider":"Anthropic","endpoint":"...","cloud":{},"keys":[],"models":[],"tag":"..."}'const credential = await mt.credentials.create({ name: "openai-production", provider: "OpenAi", keys: [{ value: process.env.OPENAI_API_KEY! }], models: [{ model: "gpt-5" }] });mt.credentials.create(name="openai-production", provider="OpenAi", keys=[{"value": os.environ["OPENAI_API_KEY"]}], models=[{"model": "gpt-5"}])credentials.delete
Section titled “credentials.delete”DELETE /credentials/by-id/{id}Deletes a credential and takes it out of every stack that holds it.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes |
Response: no body (204)
curl -X DELETE "https://api.maitento.com/credentials/by-id/<id>" \ -H "Authorization: $MAITENTO_AUTH"await mt.credentials.delete("6f1d2c3b-4a5e-4f60-8b7c-9d0e1f2a3b4c");mt.credentials.delete("3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7")credentials.get
Section titled “credentials.get”GET /credentials/by-id/{id}The credential with this id. Throws NotFoundError when there is none.
Who can call it: Admins and members, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes |
Response: ModelCredential (200)
curl -X GET "https://api.maitento.com/credentials/by-id/<id>" \ -H "Authorization: $MAITENTO_AUTH"const credential = await mt.credentials.get("6f1d2c3b-4a5e-4f60-8b7c-9d0e1f2a3b4c");mt.credentials.get("3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7")credentials.update
Section titled “credentials.update”PUT /credentials/by-id/{id}Replaces a credential’s fields. Keys are matched by id: one sent as { id } keeps its secret, and one left out is removed. New keys or a new endpoint switch a credential its circuit breaker turned off back on.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes |
Request body: ModelCredentialRequest
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ||
description | string | null | ||
provider | ModelKeyProvider | ||
endpoint | string | null | An HTTPS endpoint on the public internet; null for the provider’s public API. | |
cloud | CredentialCloudInput| null | For an Anthropic credential: Claude on Amazon Bedrock (with awsRegion) or Google Vertex AI (with gcpProjectId and gcpRegion), with no endpoint. The key is then the Bedrock API key, or the service account’s JSON key file. Only code pipelines’ Claude Code agents run on it. | |
keys | ModelCredentialKeyRequest[] | ||
models | CredentialModelInput[] | ||
tag | string | null |
Response: ModelCredential (200)
curl -X PUT "https://api.maitento.com/credentials/by-id/<id>" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"name":"...","description":"...","provider":"Anthropic","endpoint":"...","cloud":{},"keys":[],"models":[],"tag":"..."}'await mt.credentials.update("6f1d2c3b-4a5e-4f60-8b7c-9d0e1f2a3b4c", { name: "openai-production", provider: "OpenAi", keys: [{ id: "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7" }, { value: process.env.OPENAI_API_KEY_NEW! }] });mt.credentials.update("3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7", name="openai-production", provider="OpenAi", keys=[{"id": "4f5a6b7c-8d9e-4f0a-b1c2-d3e4f5a6b7c8"}], models=[{"model": "gpt-5"}, {"model": "gpt-5-mini"}]) # the key keeps its secretcredentials.replaceSignInTokens
Section titled “credentials.replaceSignInTokens”PUT /credentials/by-id/{id}/sign-in-tokensReplaces the tokens of a credential made by importSignIn, after you refreshed them. A sign-in made through startSignIn is refused with api:credentials:sign-in-refreshed-here: Maitento refreshes those itself.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes |
Request body: CredentialSignInTokensRequest
| Field | Type | Required | Description |
|---|---|---|---|
tool | CredentialOAuthTool | The coding agent the sign-in is for. | |
accessToken | string | The access token. Write-only. | |
refreshToken | string | The refresh token, which the coding agent may need during a long run. Write-only. | |
idToken | string | null | The OpenID Connect ID token. Required for Codex; null for Claude. Write-only. | |
expiresAtUtc | datetime | When the access token expires (UTC). | |
scopes | string[] | null | The scopes the tokens carry. | |
subscriptionType | string | null | The subscription the sign-in belongs to, as the provider names it (for example max). | |
accountName | string | null | Who signed in, as the provider shows it. | |
name | string | null | ||
description | string | null | ||
tag | string | null | ||
keepFresh | boolean | True: the platform keeps these tokens fresh from now on, with the refresh token, as it does for a sign-in made here. Stop refreshing them yourself: a refresh replaces the refresh token, so only one side can keep doing it. Replacing the tokens of a sign-in you’ve been refreshing with this set hands it over. Once handed over it can’t be handed back; sign in again for new tokens. False (default): you keep them fresh. |
Response: ModelCredential (200)
curl -X PUT "https://api.maitento.com/credentials/by-id/<id>/sign-in-tokens" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"tool":"Claude","accessToken":"...","refreshToken":"...","idToken":"...","expiresAtUtc":"2026-01-01T00:00:00Z","scopes":[],"subscriptionType":"...","accountName":"...","name":"...","description":"...","tag":"...","keepFresh":false}'await mt.credentials.replaceSignInTokens("6f1d2c3b-4a5e-4f60-8b7c-9d0e1f2a3b4c", { tool: "Claude", accessToken, refreshToken, expiresAtUtc });mt.credentials.replace_sign_in_tokens("3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7", tool="Claude", access_token=os.environ["CLAUDE_ACCESS_TOKEN"], refresh_token=os.environ["CLAUDE_REFRESH_TOKEN"], expires_at_utc=datetime.datetime(2027, 4, 16, 17, tzinfo=datetime.timezone.utc))credentials.test
Section titled “credentials.test”POST /credentials/by-id/{id}/testTests a credential without running a model: each key lists the provider’s models once at the credential’s endpoint. The test passes when every key does, and a passing test switches a credential its circuit breaker turned off back on. Limited to a few a minute per tenant: beyond that it throws RateLimitError.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes |
Response: CredentialTestResult (200)
curl -X POST "https://api.maitento.com/credentials/by-id/<id>/test" \ -H "Authorization: $MAITENTO_AUTH"const { succeeded, errorCode } = await mt.credentials.test("6f1d2c3b-4a5e-4f60-8b7c-9d0e1f2a3b4c");mt.credentials.test("3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7")credentials.importSignIn
Section titled “credentials.importSignIn”POST /credentials/sign-in-tokensMakes an OAuth credential from a sign-in whose tokens you already hold, such as one your own application signed in. You keep them fresh: Maitento never refreshes them, so call replaceSignInTokens each time you refresh. Tenant admins only. Never retried: a retry could make a second credential.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Request body: CredentialSignInTokensRequest
| Field | Type | Required | Description |
|---|---|---|---|
tool | CredentialOAuthTool | The coding agent the sign-in is for. | |
accessToken | string | The access token. Write-only. | |
refreshToken | string | The refresh token, which the coding agent may need during a long run. Write-only. | |
idToken | string | null | The OpenID Connect ID token. Required for Codex; null for Claude. Write-only. | |
expiresAtUtc | datetime | When the access token expires (UTC). | |
scopes | string[] | null | The scopes the tokens carry. | |
subscriptionType | string | null | The subscription the sign-in belongs to, as the provider names it (for example max). | |
accountName | string | null | Who signed in, as the provider shows it. | |
name | string | null | ||
description | string | null | ||
tag | string | null | ||
keepFresh | boolean | True: the platform keeps these tokens fresh from now on, with the refresh token, as it does for a sign-in made here. Stop refreshing them yourself: a refresh replaces the refresh token, so only one side can keep doing it. Replacing the tokens of a sign-in you’ve been refreshing with this set hands it over. Once handed over it can’t be handed back; sign in again for new tokens. False (default): you keep them fresh. |
Response: ModelCredential (200)
curl -X POST "https://api.maitento.com/credentials/sign-in-tokens" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"tool":"Claude","accessToken":"...","refreshToken":"...","idToken":"...","expiresAtUtc":"2026-01-01T00:00:00Z","scopes":[],"subscriptionType":"...","accountName":"...","name":"...","description":"...","tag":"...","keepFresh":false}'const credential = await mt.credentials.importSignIn({ tool: "Claude", accessToken, refreshToken, expiresAtUtc, name: "acme-claude-max" });mt.credentials.import_sign_in(tool="Claude", access_token=os.environ["CLAUDE_ACCESS_TOKEN"], refresh_token=os.environ["CLAUDE_REFRESH_TOKEN"], expires_at_utc=datetime.datetime(2027, 4, 16, 17, tzinfo=datetime.timezone.utc), name="acme-claude-max")credentials.startSignIn
Section titled “credentials.startSignIn”POST /credentials/sign-in/{tool}Starts signing a coding agent’s subscription in as an OAuth credential: "Claude" (Claude Code, on a Claude Pro or Max subscription) or "Codex" (on a ChatGPT subscription). Pass { credentialId } to sign an existing one in again (new tokens, same credential and stacks). Code pipelines run their agents on such a credential in place of an API key. Signing in takes two steps. For Claude, the person opens authorizeUrl, signs in, and you pass the code Anthropic shows to finishSignIn. For Codex, the person opens verificationUrl and enters userCode, and you call finishSignIn every pollIntervalSeconds until it returns Complete. Either way, finish before expiresAtUtc.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
tool | CredentialOAuthTool | yes |
Request body: CredentialSignInStartRequest
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | uuid | null | To sign an existing OAuth credential in again (new tokens, same credential and stacks); null for a new one. |
Response: CredentialSignInStart (200)
curl -X POST "https://api.maitento.com/credentials/sign-in/<tool>" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"credentialId":"..."}'const { signInId, verificationUrl, userCode, pollIntervalSeconds } = await mt.credentials.startSignIn("Codex");mt.credentials.start_sign_in("codex")credentials.finishSignIn
Section titled “credentials.finishSignIn”POST /credentials/sign-in/{tool}/finishFinishes a sign-in that startSignIn started. For Claude, pass the code Anthropic showed (as shown, # and all). For Codex, pass no code and call again every pollIntervalSeconds while it returns Pending. Once it returns Complete, credential is the saved credential; name, description and tag name a new one (a credential signed in again keeps its own).
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
tool | CredentialOAuthTool | yes |
Request body: CredentialSignInFinishRequest
| Field | Type | Required | Description |
|---|---|---|---|
signInId | uuid | ||
code | string | null | The code Anthropic shows after signing in to Claude (as shown, code#state included). | |
name | string | null | ||
description | string | null | ||
tag | string | null |
Response: CredentialSignInResult (200)
curl -X POST "https://api.maitento.com/credentials/sign-in/<tool>/finish" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"signInId":"...","code":"...","name":"...","description":"...","tag":"..."}'const { status, credential } = await mt.credentials.finishSignIn("Codex", { signInId: "9e8d7c6b-5a4f-4e3d-b2c1-a0f9e8d7c6b5", name: "team-chatgpt" });mt.credentials.finish_sign_in("codex", sign_in_id="6b7c8d9e-0f1a-4b2c-9d3e-f4a5b6c7d8e9", name="codex-team")credentials.testUnsaved
Section titled “credentials.testUnsaved”POST /credentials/testTests a credential before saving it, so a failing one never has to exist: the same checks and calls as test, on the keys in request (what create takes). Nothing is stored, and the result’s credentialId is empty. Refused with create’s codes, and shares test’s limit.
Who can call it: Tenant admins only, with an API key or a portal session. Try it in the API playground.
Request body: ModelCredentialRequest
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ||
description | string | null | ||
provider | ModelKeyProvider | ||
endpoint | string | null | An HTTPS endpoint on the public internet; null for the provider’s public API. | |
cloud | CredentialCloudInput| null | For an Anthropic credential: Claude on Amazon Bedrock (with awsRegion) or Google Vertex AI (with gcpProjectId and gcpRegion), with no endpoint. The key is then the Bedrock API key, or the service account’s JSON key file. Only code pipelines’ Claude Code agents run on it. | |
keys | ModelCredentialKeyRequest[] | ||
models | CredentialModelInput[] | ||
tag | string | null |
Response: CredentialTestResult (200)
curl -X POST "https://api.maitento.com/credentials/test" \ -H "Authorization: $MAITENTO_AUTH" \ -H "Content-Type: application/json" \ -d '{"name":"...","description":"...","provider":"Anthropic","endpoint":"...","cloud":{},"keys":[],"models":[],"tag":"..."}'const { succeeded } = await mt.credentials.testUnsaved({ name: "openai-production", provider: "OpenAi", keys: [{ value: process.env.OPENAI_API_KEY! }] });mt.credentials.test_unsaved(name="openai-production", provider="OpenAi", keys=[{"value": "sk-..."}])