Using the API
Base URLs, authentication, error codes and the role each call requires.
The Functions control plane is a Connect service
spoken over JSON. Every call is a POST to /<package>.<Service>/<Method> with
a JSON body.
https://functions.xeonr.io production
https://functions.xeonr.dev stageFrom TypeScript or a shell, prefer the SDK and CLI — it handles the conventions below, and waits for builds that finish after the call that started them returns. This page is what it speaks, and what to implement against in another language.
Per-method request and response shapes are in the API specification, generated from the proto the server implements.
| Service | What it covers | Team tokens |
|---|---|---|
xeonr.functions.v1.FunctionService | Functions, versions, deploys, files, repositories | ✓ |
xeonr.functions.v1.TeamService | Teams, members, tokens, activity | ✗ — session only |
Authentication
Either a console session cookie, or a team API token:
curl -X POST https://functions.xeonr.io/xeonr.functions.v1.FunctionService/ListFunctions \
-H "Authorization: Bearer fnt_…" \
-H "content-type: application/json" \
-d '{"teamId": "t-…"}'A token authenticates FunctionService only. Presenting one to TeamService
is refused with permission_denied, whatever the token's role.
Roles
The spec does not carry authorisation, so it is here. Every call resolves your role in the team that owns the thing you are acting on.
| Role | Calls |
|---|---|
| Viewer | List* / Get* / ReadFile, GetBuildLog, GetFunctionStats, ListRepositories, ListConnections, ListTeamActivity |
| Editor | everything above, plus CreateFunction, UpdateFunction, DeleteFunction, all deploy and promote calls, the file writes, SelectRepository, DisconnectRepository, DeleteConnection |
| Owner | everything above, plus UpdateTeam, DeleteTeam, the member calls and the token calls |
Listing tokens requires owner as well as creating them — the list is a map of what would have to be rotated.
Errors
Errors come back as a JSON object with a Connect code and a message, alongside the matching HTTP status:
{ "code": "failed_precondition", "message": "no repository is connected to this function" }| Code | Status | Typically |
|---|---|---|
invalid_argument | 400 | A malformed field, or one that does not apply to the function's kind. |
unauthenticated | 401 | Missing or invalid credentials. |
permission_denied | 403 | Your role is not enough for this call. |
not_found | 404 | No such function, version or team — also what you get for one you may not see. |
already_exists | 409 | Name collision. |
failed_precondition | 409 | Valid call, wrong state — nothing to deploy, no repository connected. |
unimplemented | 501 | Not available on this deployment, or not built yet. |
internal | 500 | Server-side failure. |
unimplemented is a real answer, not a bug. A deployment configured without a
platform client, a git provider or an encryption key reports the capability as
unavailable rather than failing obscurely — and a method this server does not
have answers the same way rather than falling through to the console's HTML
shell. A client can therefore tell "this server is older than this client" from
a typo or a broken proxy.
Conventions
- Timestamps are Unix seconds, encoded as strings — the protobuf JSON mapping for 64-bit integers.
- Enums travel as their proto names:
KIND_NODE,VERSION_STATE_READY,TEAM_ROLE_EDITOR. - Write-only fields — git credentials and secret values — are never returned. Omitting one leaves it alone; sending an empty string clears it.
- Paging is a
pageSizeplus an opaquepageToken; keep sending backnextPageTokenuntil it is empty. - Uploads are base64 in
sourceZip, up to 64 MiB.