An organization is who pays and who may do what. It holds projects, and projects hold what you buy. This guide shows the day-to-day calls to set one up and to run a team. The samples use the helper from Using the Zaroz API.
Roles
Role
Can
owner
Everything, including deleting the organization and managing other owners
admin
Buy, manage projects and members (not above their own role), create organization API tokens
billing
Pay invoices and read billing
member
Use the organization's services; see its projects, members and invoices
Two rules protect you from locking yourself out: you cannot demote or remove the last owner, and you cannot change a member whose role is above yours (403 member-outranks-caller). Anyone may remove themselves. A personal organization (every account has one) takes no other members: adding one answers 422 member-personal-organization.
You become its owner. GET /organizations lists every organization you belong to, and GET /organizations/by-slug/{slug} finds one by its slug. PATCH /organizations/{id} renames it.
Projects
A project groups services. The slug is unique inside the organization.
curl
Code
curl -sS -X POST "$ZAROZ_API/organizations/$ORG/projects" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"name": "Production", "slug": "production", "description": "Live servers"}'curl -sS -X PATCH "$ZAROZ_API/projects/$PROJECT" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"description": null}' # null clears it; omitted fields are unchangedcurl -sS "$ZAROZ_API/projects/$PROJECT/stats" -H "$AUTH"curl -sS -X DELETE "$ZAROZ_API/projects/$PROJECT" -H "$AUTH" # 204, only when it holds no subscriptions
TypeScript
Code
const project = await call("POST", `/organizations/${ORG}/projects`, { name: "Production", slug: "production",});await call("PATCH", `/projects/${project.body.id}`, { name: "Live" });const del = await call("DELETE", `/projects/${project.body.id}`);console.log(del.status); // 204, or 4xx while it still holds subscriptions
Python
Code
_, project = call("POST", f"/organizations/{ORG}/projects", {"name": "Production", "slug": "production"})call("PATCH", f"/projects/{project['id']}", {"name": "Live"})status, _ = call("DELETE", f"/projects/{project['id']}") # 204, or 4xx while it still holds subscriptions
In a personal organization the slug games is reserved for the gaming dashboard (422 project-slug-reserved) and that project cannot be changed here (403 project-gaming-managed).
Invite people
Invite by email address with the role they should get. The answer is the same whether or not the address already has an account, so the API cannot be used to find out who is registered.
Your own email must be verified before you can invite. Sending is rate-limited, and an address that declined has a 30-day cool-down before it can be invited again; both answer 429 with a machine-readable code.
The invited person, signed in with the same verified email, sees the invitation and answers it:
curl
Code
curl -sS "$ZAROZ_API/me/invitations?status=pending" -H "$AUTH"curl -sS -X POST "$ZAROZ_API/invitations/$INVITATION/accept" -H "$AUTH"curl -sS -X POST "$ZAROZ_API/invitations/$INVITATION/decline" -H "$AUTH"curl -sS -X POST "$ZAROZ_API/invitations/$INVITATION/allow-reinvite" -H "$AUTH" # lift the cool-down early
Accepting is repeatable (a second accept changes nothing) and also works on a declined, unexpired invitation. If you already belong to that organization the answer is 409 and the invitation is cancelled: accepting never changes an existing member's role.
Add, change and remove members
If you already know a person's account id you can add them directly, without an invitation.
const members = await call("GET", `/organizations/${ORG}/members`);for (const m of members.body) console.log(m.name, m.email, m.role);await call("PATCH", `/organizations/${ORG}/members/${USER}`, { role: "admin" });await call("DELETE", `/organizations/${ORG}/members/${USER}`);
Python
Code
_, members = call("GET", f"/organizations/{ORG}/members")for m in members: print(m["name"], m["email"], m["role"])call("PATCH", f"/organizations/{ORG}/members/{USER}", {"role": "admin"})call("DELETE", f"/organizations/{ORG}/members/{USER}")
Re-adding an existing member returns the membership unchanged. Reading the member list of an organization you do not belong to answers 404, the same as one that does not exist.
Billing country
A purchase in a shared organization needs the country it is taxed under. A quote answers billing-country-required until it is set. Owners and admins set it once; repeating the same value succeeds and a different one is refused with billing-country-already-set.
Proving that the organization controls a domain is done with a DNS TXT record. Start the challenge, publish the record, then ask for a check (the platform also rechecks on its own).
curl
Code
curl -sS -X POST "$ZAROZ_API/organizations/$ORG/domains" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"domain": "example.com"}'# {"domain":"example.com","record_type":"TXT","record_name":"...","record_value":"...","status":"...", ...}# publish the TXT record at record_name with record_value, then:curl -sS -X POST "$ZAROZ_API/organizations/$ORG/domains/example.com/check" -H "$AUTH"curl -sS "$ZAROZ_API/organizations/$ORG/domains" -H "$AUTH"curl -sS -X DELETE "$ZAROZ_API/organizations/$ORG/domains/example.com" -H "$AUTH"
_, challenge = call("POST", f"/organizations/{ORG}/domains", {"domain": "example.com"})print("TXT", challenge["record_name"], "=", challenge["record_value"])# after publishing the record:_, checked = call("POST", f"/organizations/{ORG}/domains/example.com/check")print(checked["status"], checked["last_error"])
The check performs a real DNS lookup and is tightly rate-limited, so wait for the record to propagate before calling it again. last_error says what the lookup found. (This proves ownership of a domain for the organization; to put a domain in front of a service see Custom domains.)
Activity log
Everything done to the organization is listed, newest first, with who did it (a person, or an API token by name). Narrow it with project_id, service_instance_id or action.
curl
Code
curl -sS "$ZAROZ_API/organizations/$ORG/audit?page=1&page_size=50" -H "$AUTH"curl -sS "$ZAROZ_API/service-instances/$SERVICE/activity" -H "$AUTH" # one service only
TypeScript
Code
const log = await call("GET", `/organizations/${ORG}/audit?page_size=20`);for (const e of log.body.data) console.log(e.created_at, e.action, e.principal_name ?? e.api_token_name);
Python
Code
_, log = call("GET", f"/organizations/{ORG}/audit?page_size=20")for e in log["data"]: print(e["created_at"], e["action"], e["principal_name"] or e["api_token_name"])
Platform-internal events never appear here: only what customers did to your organization.
Delete an organization
Only an owner can, and only when it is empty: no projects (delete them first) and no wallet balance. A personal organization cannot be deleted.