Appearance
User & account API
Everything about the signed-in user and the account they belong to. All endpoints need a bearer token (JWT or API key).
Most of this page needs no particular permission - it is about you. The three exceptions are marked: updating account contact details, the alert webhook, and the alert thresholds all need account:update, which an API key can never hold. Those three are session-only in practice.
Quick stats
http
GET /api/user/statsA small dashboard summary - how many of each resource you're running:
json
{ "pods": 3, "domains": 2, "networks": 1, "firewalls": 1 }Get your profile
http
GET /api/user/profileReturns your user record, plus the permissions resolved for this request:
json
{
"id": "6a4d5b83b7006ccae6391801",
"username": "alice",
"firstName": "Alice",
"lastName": "Smith",
"email": "[email protected]",
"lastLogin": "2026-07-16T09:41:02Z",
"isActive": true,
"isVerified": true,
"role": "user",
"accountRole": "owner",
"accountId": "6a4d5b83b7006ccae6391800",
"acceptedTermsVersion": "2026-07-22",
"acceptedTermsAt": "2026-07-16T09:41:02Z",
"createdAt": "2026-07-16T09:41:02Z",
"updatedAt": "2026-09-14T11:20:00Z",
"permissions": ["*"]
}The permissions array
permissions is what this caller may actually do, already resolved. Use it to decide which controls to draw instead of guessing from accountRole.
- The account Owner gets exactly
["*"]. One element, the global wildcard, meaning everything. - A member gets their role's grant list verbatim:
resource:actiontokens andresource:*wildcards. Expand the wildcards yourself; the API does not do it for you. - An API key gets its own scope intersected with its creator's current grants, then capped to what a key may ever hold. A key never shows
*, even one created by the Owner - it gets the expanded token list instead.
A member who somehow has no role at all comes back with "permissions": null rather than [], so check before you iterate.
A member on a custom role looks like this:
json
{
"username": "bob",
"accountRole": "member",
"accountRoleId": "6a4d5b83b7006ccae6391841",
"permissions": ["pods:*", "domains:read", "domains:update", "audit:read"]
}accountRoleId is present only for members; the Owner has no role to point at. The tokens themselves come straight from the role, so GET /api/roles/ and this array always agree. The vocabulary is documented in Team & roles.
Do not treat this array as a security boundary - it is a hint for your UI. The API enforces the same grants on every call regardless of what you drew.
Get the account
http
GET /api/user/accountAccount-level details: name, available credit, contact fields, alert settings, and your resource limits:
json
{
"id": "6a4d5b83b7006ccae6391800",
"name": "Alice's projects",
"credit": 42.5,
"email": "[email protected]",
"phone": "+1 555 0100",
"address": "123 Main St",
"taxNumber": "GB123456789",
"maxPods": 5,
"maxDomains": 10,
"maxNetworks": 10,
"maxFirewalls": 10,
"maxEmails": 0,
"maxSnapshotsPerPod": 5,
"maxBackupsPerPod": 5,
"alertWebhookUrl": "https://example.com/hooks/microapps",
"lowCreditThreshold": 5,
"monthlySpendThreshold": 50,
"createdAt": "2026-07-16T09:41:02Z",
"updatedAt": "2026-09-14T11:20:00Z"
}The max* fields are read-only. They show the ceilings on your account, and there is no customer endpoint to raise them - see Account limits. The numbers above are typical defaults for a fresh account (maxEmails stays 0 until email hosting is enabled on request); check your own account for the real ones. maxBackupsPerPod stops applying once paid backups start: it stays in the response, but nothing enforces it.
If your account is in dunning or suspended, this response also carries dunningStage, dunningStopAt, dunningDeleteAt, or suspended and suspendedAt. A healthy account omits all of them.
Change your password
http
POST /api/user/change-passwordjson
{
"currentPassword": "Sup3rSecret",
"password": "N3wSecret",
"passwordConfirm": "N3wSecret"
}The new password needs 8+ characters with an uppercase letter, a lowercase letter, and a digit. A wrong currentPassword returns 401.
Returns 204 No Content. Changing your password signs out every session - including the one that made this call - so log in again with the new password.
Update your profile
http
PUT /api/user/profilejson
{ "firstName": "Alice", "lastName": "Jones" }Returns the updated user. Each name is capped at 60 characters.
Change your email
http
PUT /api/user/emailjson
{ "email": "[email protected]", "currentPassword": "Sup3rSecret" }We ask for your current password because an email change is sensitive. The new address has to be verified again - and until you click the verification link, calls under /api return 403. Watch for the email. Returns the updated user with isVerified back to false.
| Problem | Status |
|---|---|
Wrong currentPassword | 401 |
email is already your address | 400 |
email belongs to another user | 409 |
Accept the current terms
http
POST /api/user/accept-termsNo body. Records that you accept the current version of the legal documents, and returns 204 No Content.
Compare the acceptedTermsVersion on your profile against termsVersion from GET /open/legal. If yours is behind, the documents have changed and the console puts a consent prompt in front of everything else; this is the call that prompt makes.
Update account contact details
http
PUT /api/user/accountNeeds account:update.
json
{
"name": "Alice's projects",
"email": "[email protected]",
"phone": "+1 555 0100",
"address": "123 Main St",
"taxNumber": "GB123456789"
}These details show up on your invoices. This endpoint deliberately can not touch your resource limits - there is no self-service way to raise your own ceilings here. Returns the updated account.
Every field is optional and sending an empty string clears it. Lengths are capped at 120 (name), 40 (phone), 240 (address) and 60 (taxNumber) characters; go over on any of them and you get one 400: "One or more fields exceed the maximum length".
Alert webhook
http
PUT /api/user/alert-webhookNeeds account:update.
json
{ "url": "https://example.com/hooks/microapps" }Where we POST account alerts, such as a low-credit warning. One URL per account. Send {"url": ""} to turn it off.
The URL must be http or https with a host, and it must resolve to a public address - a webhook aimed at private infrastructure is rejected with 400 ("Webhook must point to a public address").
json
{ "message": "Alert webhook updated" }Alert thresholds
http
PUT /api/user/alert-thresholdsNeeds account:update.
json
{ "lowCreditThreshold": 5.0, "monthlySpendThreshold": 50.0 }These are alerts only. When your credit drops below lowCreditThreshold, or your month's usage crosses monthlySpendThreshold, we let you know (by email, and via your webhook if you set one). They never auto-charge a card or cap anything - MicroApps is prepaid, so nothing is billed unless you top up first.
Set either to 0 to disable that alert. Negative values return 400.
json
{ "message": "Alert thresholds updated" }Example
bash
curl https://cloud-api.microapps.io/api/user/account \
-H "Authorization: Bearer $MICROAPPS_API_KEY"Check what the current credential is allowed to do:
bash
curl -s https://cloud-api.microapps.io/api/user/profile \
-H "Authorization: Bearer $MICROAPPS_API_KEY" | jq .permissions