API
Every action in Frazer is an API method first. The console, the CLI, the MCP server and the Terraform provider call the same handlers, so permissions, plans, quotas and audit records are the same whichever you use. The API is generated from protobuf contracts that follow the API Improvement Proposals (AIP), and the REST, gRPC and Connect surfaces, the CLI, the MCP tools, the provider and the SDKs all come from those contracts.
Base URLs
Section titled “Base URLs”| Host | Serves |
|---|---|
https://api.frazer.ai |
gRPC, Connect and gRPC-Web, and REST under /<service>/v1/… |
https://mcp.frazer.ai |
The MCP server for AI agents |
<service>.<region>.frazer.ai |
Regional data planes, such as registry.us-virginia1.frazer.ai for Registry |
Each product is a service with a one-word ID, for example resourcemanager (organizations and projects), iam, approvals, kubernetes, serverless, databases, keyvalue (the in-memory store), storage, registry, secrets, network, dns, monitoring, ai, llm, agents, devboxes, runners, billing and quota. A service’s REST paths start with its ID, and its gRPC package is frazer.<service>.v1.
Authentication
Section titled “Authentication”Send a token in the Authorization header:
curl https://api.frazer.ai/resourcemanager/v1/projects/acme-staging \ -H "Authorization: Bearer $FRAZER_TOKEN"| Credential | Use it for | Lifetime |
|---|---|---|
Personal access token (frz_pat_…) |
Scripts and tools you run | Expiry required: up to 365 days, 90 by default; an organization can cap it |
| Workload identity federation | CI jobs and workloads, with no stored key | 15-minute tokens |
| Service account key | Systems that cannot federate; off by default | Up to 90 days when the organization allows keys |
CLI sign-in (frazer login) |
Your terminal | 15-minute access tokens, refreshed for up to 90 days |
| OAuth 2.1 (MCP clients and apps) | Agents and connected apps | 15-minute access tokens, refreshed for up to 30 days |
Personal access tokens
Section titled “Personal access tokens”Create one under Account › Personal access tokens and CLI tokens in the console. Creating a token needs a passkey or second factor from the last 10 minutes, and a token can never create another token. Frazer shows the token once and stores only its hash.
- A token is bound to one organization. A call on another organization’s resource fails with
ORG_RESTRICTED. - A token carries scopes, and it never allows more than you hold yourself.
allowed_networkslimits a token to up to 20 IPv4 or IPv6 prefixes; a call from anywhere else is refused before any permission check.- The token page shows when and from which address each token was last used. Frazer emails you 7 days and 1 day before a token expires.
Scopes
Section titled “Scopes”| Scope | Allows |
|---|---|
<service>:read |
The service’s read and list permissions, for example kubernetes:read |
<service>:write |
Every permission of the service except IAM changes and data access |
cloud-platform |
Every permission you hold |
A permission outside a token’s scopes is denied with deniedBy: token_scope.
Audiences and bound tokens
Section titled “Audiences and bound tokens”Every access token names one audience: https://api.frazer.ai or https://mcp.frazer.ai. A token minted for one is refused by the other. Access tokens are signed JWTs.
Tokens the CLI holds are bound to the device’s key (DPoP): they travel as Authorization: DPoP with a fresh proof on each request, and the same token sent as Bearer is refused. For scripts, use a personal access token or workload identity federation.
Workload identity federation
Section titled “Workload identity federation”A GitHub Actions or GitLab job, or a workload in a Frazer cluster, exchanges its own signed identity token for a 15-minute Frazer token. A condition on the token’s claims decides which jobs may, for example repository == "acme/platform-envs" && ref == "refs/heads/main". Nothing secret is stored in CI. See Identity and access.
REST, gRPC and Connect
Section titled “REST, gRPC and Connect”All protocols are served on api.frazer.ai, on one port, by the same handlers.
curl https://api.frazer.ai/resourcemanager/v1/projects/acme-staging \ -H "Authorization: Bearer $FRAZER_TOKEN"curl https://api.frazer.ai/frazer.resourcemanager.v1.ProjectService/GetProject \ -H "Authorization: Bearer $FRAZER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "projects/acme-staging"}'- REST paths are
https://api.frazer.ai/<service>/v1/<resource name>. Custom methods end in:verb, for examplePOST https://api.frazer.ai/iam/v1/organizations/acme/decisions:troubleshootAccess. - gRPC and Connect use the service names of the contracts, such as
frazer.resourcemanager.v1.ProjectServiceorfrazer.approvals.v1.ApprovalService. gRPC-Web is served too. - Streams such as
WatchOperationexist on gRPC and Connect only. REST clients poll instead. - OpenAPI 3.1 descriptions of the REST surface and the Go (
go.frazer.ai/sdk) and TypeScript (@frazer-aion npm) SDKs are generated from the same contracts.
Resource names
Section titled “Resource names”Every resource has a name that is also its path:
organizations/acmeprojects/acme-productionprojects/acme-production/locations/us-virginia1/clusters/acme-production-1projects/acme-production/managedZones/appsorganizations/acme/decisions/<decision>- Projects first. Project IDs are unique across Frazer, so a project’s resources are named from the project. The organization is the project’s parent, not part of the name, so moving a project to another organization renames nothing. Only a small set of collections, such as decisions and verified domains, live under
organizations/<organization>. - Locations. Regional resources carry
locations/<location>, a region such asus-virginia1(Virginia, USA).globalis a location too. - IDs you choose are lowercase letters, digits and hyphens, start with a letter and are at most 63 characters. Project IDs are 6 to 30 characters and never reused; organization IDs are 4 to 24. IDs starting with
frazer,googorsystemare reserved. Every resource also has auidthat is never reused. - Full resource names add the service:
//kubernetes.frazer.ai/projects/acme-production/locations/us-virginia1/clusters/acme-production-1. Events and Terraform imports use them, andhttps://console.frazer.ai/r/<full resource name>opens any resource in the console.
Resources share standard fields:
| Field | Meaning |
|---|---|
name, uid |
The resource name and the system ID |
display_name, labels, annotations |
Your descriptions. Labels are metadata only and never used in policy; tags are |
create_time, update_time, delete_time, purge_time |
When it was created, changed, deleted and will be purged |
etag |
The version, for safe updates |
state, reconciling |
Its state, and whether Frazer is still converging it |
generation, observed_generation |
The version of the spec, and the one Frazer has applied |
Labels: up to 64 per resource; keys and values up to 63 characters of a-z, 0-9, _ and -.
Methods
Section titled “Methods”| Method | REST | Notes |
|---|---|---|
| Get | GET on the name |
|
| List | GET on the collection |
Pagination and filtering |
| Create | POST on the collection |
You choose the ID |
| Update | PATCH on the name |
Only the fields in update_mask change |
| Delete | DELETE on the name |
A soft delete; see Soft delete |
| Undelete | POST on :undelete |
Before purge_time |
| Custom | POST on :verb |
Such as :upgrade or :troubleshootAccess |
Every mutation takes validate_only and request_id; every mutable resource has an etag.
Long-running operations
Section titled “Long-running operations”A mutation that can take more than a second returns an operation:
GetOperationandListOperationsread operations; done operations stay readable for at least 30 days.WatchOperationstreams progress on gRPC and Connect, and a watch that breaks resumes where it stopped. Over REST, pollGetOperation.CancelOperationcancels where a method supports it, and answersCANCEL_NOT_SUPPORTEDwhere it does not.- An operation’s name is
projects/<project>/locations/<location>/operations/<operation>, ororganizations/<organization>/operations/<operation>for an organization-level resource.
Plans: validate_only
Section titled “Plans: validate_only”Every mutation accepts validate_only. Frazer runs every check of the real call (permissions, organization policy, quota and cost) and changes nothing; no audit record is written. The answer is the plan:
- A long-running method returns a done operation with no name: its
metadata.planis the plan, and itsresponseis the resource as it would be. - A method that answers at once returns the resource as it would be.
| Plan field | Meaning |
|---|---|
changes |
Each resource created, changed or deleted: the action, the resource and its type |
quota_impacts |
Per quota counter: the metric, scope, location, limit, usage and the amount requested |
policy_violations |
Organization policy the change would break |
estimated_cost |
The cost per month, as a currency amount |
warnings |
For example, a counter at 80 % or more of its limit after the change |
A plan over a quota fails with the same QUOTA_EXCEEDED error the call itself would return, with the numbers and a link to request more. frazer … --dry-run, the console’s Plan step, MCP write tools and terraform plan all use validate_only.
Approvals
Section titled “Approvals”When a rule holds a call for a person’s approval, the call changes nothing and answers FAILED_PRECONDITION with reason APPROVAL_REQUIRED in domain approvals.frazer.ai:
- metadata
approval(its name),planHash,expireTime,ruleandstate; - a
Helplink to the approval’s page,https://console.frazer.ai/approvals/<approval name>; - the plan, and the
X-Frazer-Approvalresponse header.
Retrying with the same request_id returns the same approval. Once approved, Frazer applies the call itself, exactly once, as the caller, and with the plan it showed: if the target changed in the meantime, the approval fails with PLAN_CHANGED. Approvals are resources of the approvals service (GetApproval, ListApprovals; :approve, :reject, :cancel), and approving needs a person with a passkey or second factor from the last 10 minutes. See Identity and access.
Pagination
Section titled “Pagination”List methods take page_size and page_token and return next_page_token. Pass the token back unchanged to get the next page; it is opaque and signed. An empty next_page_token means the last page. Pages are read by key, never by offset.
Where a method allows it, projects/- as the parent lists across every project you can read. Results from places Frazer could not reach are named in unreachable rather than silently left out.
Filtering and ordering
Section titled “Filtering and ordering”List methods take a filter in the AIP-160 syntax and an order_by on the fields the method allows:
can_decide = true AND state = PENDINGA list returns what you may see: everything when you may list the collection, otherwise the resources you were granted directly.
Idempotency
Section titled “Idempotency”Every mutation takes a request_id, a UUID you generate. A retry with the same ID and the same request returns the first answer for 7 days, so a create that timed out never runs twice. The same ID with a different request fails with REQUEST_ID_REUSED. The CLI sets a request ID on every invocation, and the Terraform provider keeps one per create in its state.
Concurrent changes: etags
Section titled “Concurrent changes: etags”Every mutable resource has an etag. Send it with an update or delete; if the resource changed since you read it, the call fails with ABORTED and reason ETAG_MISMATCH. Read the resource again, reapply your change and retry. Some methods require an etag, such as setting a whole IAM policy.
Soft delete
Section titled “Soft delete”Delete is soft: the resource gets a delete_time and a purge_time, and Undelete restores it until then. A deleted project, for example, stops billing and suspends its resources at once, and can be restored for 30 days; after that it is purged and its ID stays reserved. A lien on a project blocks its deletion with LIEN_PRESENT.
Rate limits
Section titled “Rate limits”Frazer admits every request before it does any work:
- Rate limits per principal and per organization, weighted by each method’s cost; large pages cost more.
- Fair queues per organization, then per project, so one organization’s burst does not starve another.
- Priorities: interactive calls from the console and CLI first, then automation (MCP, Terraform, SDKs and service accounts), then batch work such as exports and large lists.
A refused request gets RESOURCE_EXHAUSTED (HTTP 429) with reason RATE_LIMITED or CONCURRENCY_LIMITED, or OVERLOADED when Frazer is shedding load, each with a RetryInfo delay. Wait at least that long before you retry, and retry a mutation only with the same request_id.
Versioning and deprecation
Section titled “Versioning and deprecation”| Version | Promise |
|---|---|
v1 |
Stable: no breaking changes. A new major version comes with at least 12 months’ notice |
v1beta1 |
At least 90 days’ notice before a breaking change |
v1alpha1 |
May change; an organization opts in per feature |
A deprecated method or field answers with a Deprecation response header, the CLI warns, MCP tools are marked, and a deprecation.announced event goes out. Error reasons and metadata keys are added but never removed or reused; treat a value you do not know as the generic case.
Errors
Section titled “Errors”Errors follow one model on every protocol: a status code, an ErrorInfo with a reason, the domain of the service that refused (<service>.frazer.ai) and metadata, plus details such as field violations, QuotaFailure, RetryInfo and Help links.
{ "error": { "code": 403, "status": "PERMISSION_DENIED", "message": "The caller does not have the permission this method needs on the resource (or it might not exist).", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "PERMISSION_DENIED", "domain": "iam.frazer.ai", "metadata": { "permission": "kubernetes.clusters.get", "resource": "projects/acme-production/locations/us-virginia1/clusters/acme-production-1", "deniedBy": "allow", "rolesGranting": "roles/kubernetes.viewer", "decisionId": "0192f3a1-7c2e-7b4d-9e10-3f6a2b8c5d47" } } ] }}Errors explains every field, how to replay a denial by its decision ID, and every reason with its fix.
Response headers
Section titled “Response headers”| Header | When |
|---|---|
X-Frazer-Authz-Decision |
Every response: the ID of the permission decision, allowed or not |
X-Frazer-Approval |
The call is held: the approval’s name |
X-Frazer-Iam-Revision |
After an IAM change: the organization’s IAM revision |
X-Frazer-Access-Change |
After an IAM change: EQUIVALENT, MORE_PERMISSIVE, LESS_PERMISSIVE or INCOMPARABLE |
Deprecation |
The method or a field you used is deprecated |
Related
Section titled “Related”- CLI: every method as a command
- MCP: the API as tools for AI agents
- Errors: the error model and every reason
- Terraform and OpenTofu: the API’s resources as code
- Webhooks and events: changes pushed to you
- Identity and access: roles, tokens and approvals