Skip to content

Organizations, roles and API keys

Access in Sync Server has three layers: who you are (a session, an app token, or an API key), what org you’re in (which carries a role), and what the base allows.

Membership is per organization, and a base belongs to an org.

Role Can
viewer Read the org’s bases
member Everything a viewer can, plus edit records, attachments, trigger syncs, roll back
admin Everything a member can, plus manage members, invites and API keys
owner Everything, plus delete the org

“Write access to a base” throughout the documentation means member or better, or an API key with write permission covering the base.

A base can also be marked public, which makes it readable without any credential at all. Public never implies writable.

Credential Sent as For
Session cookie Automatic, same origin The Sync Server UI
App token (JWT) Authorization: Bearer …, ?token=, or a token form field Browser apps — see Authenticating a browser app
API key (ims_…) The same three places Servers, scripts, GIS clients, MCP

Keys come in two scopes:

  • Org keys (/api/v0/orgs/{orgId}/keys) — every base in the org.
  • Base keys (/api/v0/bases/{baseId}/keys) — exactly one base.
Terminal window
curl -X POST 'https://{SERVER}/api/v0/orgs/{orgId}/keys' \
-H 'Content-Type: application/json' \
-d '{
"name": "Nightly ETL",
"permissions": "write",
"expiresAt": "2027-01-01T00:00:00Z",
"allowedIps": ["203.0.113.0/24"],
"rateLimitPerMinute": 120
}'

The full key is returned once, at creation. Only a hash is stored; afterwards you see the 12-character prefix, the name and usage stats.

Field Meaning
permissions read (default), write, or admin
expiresAt Expiry timestamp. Omit for a key that never expires
allowedDomains Origin/referrer allowlist — for a key that will sit in a browser
allowedIps CIDR allowlist (IPv4)
rateLimitPerMinute, rateLimitPerHour Request ceilings for this key
enabled Flip to false to suspend without deleting

Every key records lastUsedAt and usageCount, so you can find the ones nobody uses.

GET|POST /api/v0/orgs/{orgId}/keys
PATCH|DELETE /api/v0/orgs/{orgId}/keys/{keyId}
GET|POST /api/v0/bases/{baseId}/keys
PATCH|DELETE /api/v0/bases/{baseId}/keys/{keyId}

Requires admin in the org.

GET|POST /api/v0/orgs
GET|PATCH|DELETE /api/v0/orgs/{orgId}
GET /api/v0/orgs/{orgId}/members
PATCH|DELETE /api/v0/orgs/{orgId}/members/{userId}
GET|POST /api/v0/orgs/{orgId}/invites
DELETE /api/v0/orgs/{orgId}/invites/{inviteId}
POST /api/v0/invites/accept

An invite is an email plus a role, and is good for 7 days. Re-inviting the same address refreshes the existing invite rather than creating a second one. The invitee accepts by posting the token to /invites/accept, which creates their membership.

Users authenticate with whichever of these the deployment configures: ArcGIS, Airtable, NocoDB, Microsoft Entra, or an emailed magic link. Sessions are stateless signed JWTs. The magic-link form is protected by a bot check.