Projects, usage and billing, quotas, compliance cases, support tickets, and the emergency stop. Per-resource facts are in VMs and email.
Conventions every call below obeys — auth, errors, idempotency — are in API conventions.
Everything you run — VMs, volumes, email domains and credentials, usage, tickets, compliance cases — lives in a project. Signup creates the account's first project; none is special.
A write or read key belongs to the project it was minted into and cannot
touch any other; it needs no header. An admin key belongs to the whole account
and has no project of its own: every call to VMs, volumes, email, usage,
support or compliance names the project it is about with a header,
AGIdock-Project: proj_...
and without one is refused with 400 project_required — no project is picked
for you.
Account-level calls (account, keys, projects, billing, images) need no
header; minting a write or read key reads it, below.
Naming a project the account does not hold is 404 project_not_found; a
write or read key naming any project but its own is
403 key_project_mismatch.
GET /v1/projects every project, archived ones included
POST /v1/projects {"name": ...} create one (admin key)
PUT /v1/projects/{id} {"name": ...} rename (admin key)
POST /v1/projects/{id}/archive revoke its keys, refuse new (admin key)
POST /v1/projects/{id}/unarchive accept new keys again (admin key)
Creating a project needs one cleared payment on the account; signup credits
do not count. Until then it is 403 payment_required, which only your human
can clear.
To mint a write or read key into a project, name the project in the
AGIdock-Project header on POST /v1/account/keys.
Archiving revokes every key in the project and refuses new ones. Nothing else changes: the project's VMs keep running and billing. An admin key can still reach an archived project through the header, so stop its VMs yourself if you want them stopped. Unarchiving does not bring the revoked keys back.
The list endpoints answer for one project at a time. The balance and the ledger are the account's, but usage, quotas, tickets and compliance cases are per project — an admin key watching the whole account asks each project.
GET /v1/usage?group_by=meter — your metered consumption, counted per
hour. from/to are RFC3339 and select every hour the window overlaps, so a
from inside the current hour returns that hour rather than nothing; the
response includes the window it used. The hour in progress is included and
flagged provisional until it closes (15 min after it ends).GET /v1/billing/balance — what is left, split grant vs paid, plus the
spend per hour (burn_rate_micro_per_hour) and runway_hours, the hours
left at that rate. held_grant_micro is starter credits waiting for your
human to save a card; they are not in the balance until then. Poll runway_hours; responses also carry an
X-Credits-Low header once the balance is close enough to the cutoff to act
on.GET /v1/billing/ledger — every debit links to the usage that caused it.
Usage is debited hourly, so the ledger is mostly debit entries:
?exclude=debit leaves only money in and out (top-ups, refills, grants,
expiries, corrections) and ?kind=topup,adjustment asks for kinds by name.
Poll the filtered view to see whether a payment arrived; the unfiltered one
is the full record.GET /v1/billing/prices — the live price book: every meter once, at the
price charged now, under one effective_from for the whole book. prices
is what you are billed today. An announced
change comes back under scheduled, grouped by the day it takes effect, at
least 30 days ahead of it. The route is public (no key, no account), and it
is the only published copy: the pricing page on the site reads this same
endpoint.Hours where the platform cannot confirm your VM was up are not billed.
Only your human can add credit
(human-only routes). GET /v1/billing/refill
works with your key and reports the automatic refill ceiling.
What happens when the balance reaches zero is under credit_cutoff in
the error reference.
GET /v1/billing/referral answers the account's referral code and its
offer: what an account that signs up with the code gets, and
reward_micro, the credits paid to this account when that account first
pays. Both are absent while no referral offer is running, and code is also
absent until the account has one cleared payment. The sign-up link is
https://dashboard.agidock.cloud/join/<code>.
offer gives, once.Three totals are capped per project, and nothing else is:
| Quota | Default |
|---|---|
| RAM across all VMs | 35 GB |
| Root disk across all VMs | 5120 GB |
| Volume storage | 10240 GB |
VM count, vCPU and IPv4 addresses are uncapped: the RAM cap limits them.
GET /v1/quota returns the caps on your project and your usage against each;
a negative cap is unlimited. 403 quota_exceeded states the quota, your
usage, what you asked for and the cap. Ask for a raise with a ticket naming
the numbers you want.
Outside these caps, what stops you is your credit balance, or one of two
refusals that are not quotas: 409 no_capacity_available (no room for that
much RAM right now) and 409 ip_pool_exhausted (no address free). Raising a
quota helps with neither.
Email is limited separately, by a daily recipient count that rises with clean sending history: email.
Abuse and DMCA complaints against your account are opened as cases at
GET /v1/compliance/cases. Opening one also mails your human, as does every
reply from our side. That mail goes to a mailbox you do not hold; the
complaint, the deadline and the thread are all on the API. Poll it on the same
schedule you check anything else that can stop your machines; an empty list is
the normal answer.
A case carries id, type (spam, ddos, dmca, fraud), body (the
complaint as received, or what we are doing and why), deadline, messages,
state (open, deadline-exceeded, closed), waiting_on (customer or
operator) and timestamps. waiting_on: customer is work you have to do or
hand to your human, and deadline says by when: **miss it and enforcement
escalates** — content takedown, or your VMs stopped.
Act before you answer: take the named content down, or stop whatever caused the complaint, then say what you did and when. A reply alone does not stop enforcement, and no endpoint extends a deadline.
Answer with POST /v1/compliance/cases/{id}/response {"response": "..."}.
messages is the thread from both sides and it appends: a second reply adds to
the record, it never replaces the first — so a short acknowledgement now and a
fuller answer once you have investigated is better than silence. A closed case
takes no more replies. There is no counter-notice endpoint: if a DMCA
claim is wrong, say so in the response and give your reasons; the thread is
kept as the record.
Every enforcement action has a case, so nothing is done to the account that you cannot read and answer here — including while you are credit-capped or suspended, where both compliance calls keep working. The deadline runs in those states too.
A human reads every ticket, and the endpoint works while you are credit-capped and while the account is suspended: use it for billing disputes and appeals.
POST /v1/support/tickets {"type":"bug"|"billing"|"feedback"|"other",
"subject":..., "body":...,
"ref": optional resource id}
GET /v1/support/tickets list yours and their states
GET /v1/support/tickets/{id} open -> answered -> closed
POST /v1/support/tickets/{id}/messages reply in the thread
POST /v1/support/tickets/{id}/close close it yourself when done
type sorts the ticket; it does not set its priority. bug for something
behaving wrongly, billing for a charge you dispute, other for anything
else that needs an answer.
feedback does not need a problem to report. Suggestions, an endpoint
you expected and did not find, a limit that does not fit how you work, a guide
that misled you — file it. This is the only channel for it: there is no forum
and no issue tracker, and the addresses on the legal pages take legal notice
and third-party abuse reports, not support. File it yourself rather than
asking your human to send it. Nobody may reply, so close your own feedback
tickets — an unanswered one stays open and counts toward the 5-ticket limit
below.
ref is a resource id the ticket is about — a vm_..., or a ledger entry id
for a billing dispute. Subject ≤ 200 chars, body ≤ 64 KiB, text only. Max 5
open tickets per project (409 ticket_cap_reached — add a message to an
existing one rather than opening another).
Poll GET /v1/support/tickets/{id} for the answer; answered auto-closes
after 14 days with no reply. The account's human gets an email when we
reply, but the thread is in the API and you continue it there.
POST /v1/account/freeze suspends the account immediately — every project in
it, so it takes an admin key (403 admin_key_required otherwise). Within 60
seconds every API key on the account — including the one that called it —
answers 403 account_suspended on every route except the four needed to
recover from the freeze: POST /v1/account/unfreeze, GET /v1/account,
everything under /v1/compliance, and everything under /v1/support.
Nothing is deleted, and running VMs keep running; only API calls stop.
An admin key can freeze the account; only your human can unfreeze it.
POST /v1/account/unfreeze is human-only (403 human_required) and also
takes a current authenticator code in the body. A code read out to you does
not help: the call refuses your key before it looks at the code.
Your human has the same freeze in the dashboard, alongside a "stop all VMs" control that stops the machines as well.