---
title: "Projects and keys"
description: "An account pays, has members and is mailed its notices at a verified address; its projects hold everything else. API keys belong to one project and have scopes; tokens open one sandbox; the console signs people in."
---

> Documentation Index
> Fetch the complete documentation index at: https://glac.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Projects and keys

## Accounts and members

An account is what pays: it has a [plan](/docs/platform/pricing/), a balance and members. Each member is an `owner`, an `admin` or a `member`:

| Role | What it may do |
|---|---|
| `owner` | Everything: the account's billing and its members, and closing the account. An account always has an owner. |
| `admin` | Everything but billing and owners: in projects, as an owner; invite and remove admins and members, and change their roles. |
| `member` | The projects, and their sandboxes, Cubes and keys (without the `admin` scope). |

People sign in to the [console](https://console.glac.ai/console/) with an email address and a password, or with GitHub or Google where the console shows their buttons; an invitation to an account is taken the same ways. An account has one or more projects.

## Where notices go

An account's notices are mailed to its address. Set it with `glac account email ADDRESS` (`PATCH /v1/account` with `email`, which takes the `admin` scope), or in the **Mail** part of the console's **Billing** page, which also lists every mail sent to the account, with its words (`GET /v1/billing/notices`, `glac billing notices`).

- **Only a verified address is mailed** (`email_verified` of `GET /v1/account`). An address is verified at once where the account had it verified already, or where it is the verified address of one of the account's members. Any other is mailed a link that verifies it, good for 7 days, and the account's notices wait until it is opened. Setting the address again, the same one too, mails a new link, and the old one stops working; so does **Send the link again** in the console. Three links an account, then one every ten minutes (429 `rate_limited`).
- **Mail that bounces.** Once mail to the address bounces, or whoever reads it marks it as unwanted, no notice goes there (`email_undeliverable`: `why` is `bounced` or `complained`, with `since` and the sender's `detail`). The notices wait until the address is set again, the same one too.
- **While notices wait**, nothing that counts from a notice starts: the 30 days before what an account in debt stores is deleted count from when the first notice of its debt is delivered.
- **A member who changes their own address** takes with them the notices of the accounts they are a member of that went to the old one.

What is mailed:

| Notice | When |
|---|---|
| `purchase_confirmed`, `withdrawal_received` | A purchase (a top-up, a plan); a withdrawal from one, acknowledged at the address the withdrawal gave. |
| `included_80`, `included_100`, `storage_80`, `storage_100` | An account that holds no balance, and that auto reload will not top up, has used 80%, then all, of what its plan includes of a meter, or of storage. |
| `in_debt`, `reminder_…` (by the day), `charge_failed`, `data_deleted` | The account owes for storage; a reminder on each of days 7, 14, 21, 27 and 29; a charge of the debt to its card failed; what it stored was deleted. See [an account that owes](/docs/platform/pricing/#an-account-that-owes). |
| `subscription_charge_failed`, `subscription_ended` | A renewal of its plan could not be charged; it was not paid within the days of grace, and the account is on Free. |
| `reload_failed`, `reload_no_card`, `reload_no_request` | An auto reload could not be charged, has no card, or waits for the buyer's request. |
| `credits_expiring_…` (by the days left) | Some of its Credits lapse in 30, 7 and 1 days. |
| `tax_address_confirm`, `tax_payment_held` | Its billing address is to be confirmed; a payment is held for support to look at. |
| `account_held` | The account was put on hold: see [`account_held`](/docs/errors/#account_held). |
| `verify_account_email` | The link that verifies its address, mailed to that address. |

## Projects

A project holds everything else: its keys, Cubes, sandboxes, snapshots, Drives and volumes, secrets, shared variables and domains. A name is unique within its project. A key sees only its own project.

`GET /v1/project` (`glac project`) gives the key's project: its id, its name, its home region, the address ranges of its private network, and after how many days asleep its sandboxes are deleted (`PATCH /v1/project` with `delete_after_idle_days`, `glac project --delete-after-idle-days 30`: see [deleted when it sleeps too long](/docs/sandbox/sleep/#deleted-when-it-sleeps-too-long)). A project can have a monthly spend limit of its own: see [spend limits](/docs/platform/pricing/#spend-limits-on-projects-and-sandboxes).

## Services {#services-with-a-volume-of-their-own}

Every Cube is a service of its project. Services find each other on the project's private network, share variables, deploy together, keep their data on a Drive of their own, and can be imported from a Compose file: see [services and Compose](/docs/cube/services/).

## API keys

A key (`ak_…`) belongs to one project and has scopes. Make one on the console's **API keys** page, or with `POST /v1/keys` (`{name, scopes, expires_at}`, every field optional; `glac keys create`, `glac.keys.create()` in Python). The key is shown once, in the answer that makes it: keep it somewhere safe. A key without chosen scopes has every scope but `admin`. `DELETE /v1/keys/{id}` revokes one at once.

| Scope | What it opens |
|---|---|
| `read` | Reading sandboxes, snapshots, Drives and volumes, usage, the account, the bill, events, Cubes, the project and its variables; the names of secrets. |
| `write` | Making, changing and deleting sandboxes, snapshots, Drives, volumes and Cubes; sleep, restart, fork, restore; deploys and rollbacks; shared variables. |
| `exec`, `files`, `tty`, `url` | Running commands, files, terminals, links to ports. |
| `admin` | Keys, SSH keys, webhooks, spend limits, the audit log, the account's settings, billing and top-ups, secrets and domains. |

A key too narrow for a call is answered 403 `key_scope`; an expired one 401 `expired_api_key`.

Every tool reads the same two environment variables:

```bash
export GLAC_API_URL=https://api.glac.ai
export GLAC_API_KEY=ak_...
```

## Other credentials

- **A token for one sandbox** (`st_…`) opens that sandbox only, with some of the scopes `url`, `exec`, `files` and `tty`, for an hour unless you say: see [tokens](/docs/sandbox/access/#tokens-for-one-sandbox).
- **SSH keys** open the project's sandboxes through the SSH gateway: see [SSH](/docs/sandbox/access/#ssh).

## How the API answers

- JSON in and out, `snake_case`, times in RFC 3339, sizes in bytes (`_bytes`), durations in seconds (`_seconds`) or milliseconds (`_ms`). Ids carry their type: `sbx-`, `exe-`, `snap-`, `vol-`, `app-`, `ver-`. Where an id is taken, a name is too.
- **Errors** have one shape: `{"error": {"type", "code", "message", "param", "retryable", "request_id", "docs_url"}}`. `code` is for programs, `message` for people; `retryable: true` means the same call again later may work, with `Retry-After` where it says when; `docs_url` leads to the code on the [errors](/docs/errors/) page. Every answer carries `X-Request-Id`.
- **Lists** are pages: `?limit=` (1 to 1,000, 100 unless you say) and `?cursor=` from the last page's `next_cursor`, newest first.
- **`Idempotency-Key`** on a `POST` (1 to 255 characters): the same key and body again within 24 hours gives the first answer, and does nothing twice. The SDKs send one with every `POST`.
- **Events**: `GET /v1/events` lists what happened in the project (`sandbox.created`, `drive.attached`, `balance.used_up`, …), and webhooks deliver them to a URL of yours, signed with the webhook's secret (`POST /v1/webhooks`, `glac webhooks create`, `glac.webhooks.create()` in Python). `GET /v1/audit` lists who changed what: every call that was no reading, a refused one too, with who made it, and every reading of an app's log by an operator (`glac audit`, the SDKs' `audit`, the MCP server's `project_audit`; a key with the `admin` scope).

The [API reference](/docs/api/) has every call.

Source: https://glac.ai/docs/platform/projects/index.mdx
