Zelt's Public API lets you connect your workspace to other tools and programmatically work with your data. To use the API, you create an app in Zelt, assign it the correct permissions, and generate an access token. Every API request must include this token in the Authorization header.
Credential types
| Credential | Description | Usage |
|---|---|---|
| Client ID | Public identifier for your app | OAuth flow only, not in API calls |
| Client secret | Private key for your app | OAuth flow only, never in API calls |
| Authorization code | Short-lived one-time code (expires in 3 minutes) | Exchanged once for an access token |
| Access token | The token you use to authenticate API calls | Authorization: Bearer header on every request |
| Refresh token | Long-lived token to get new access tokens | Token refresh endpoint only |
You cannot make API calls until you have completed step 3 and obtained an access token. Client ID and Client secret are not substitutes for an access token.
Prerequisites
- A Zelt account with admin access
- Permission to create and manage apps
- Basic familiarity with HTTP requests and JSON
What you’ll do next
Complete these steps in order; each step depends on the previous one:
- Create an app and get your Client ID and Client secret
- Choose the permissions (scopes) your app needs
- Generate an authorization code and exchange it for an access token and refresh token
- Use the access token to authenticate your API calls
- Use the refresh token to get new access tokens without repeating the full flow
You must complete steps 1-3 before making any API calls.
After that, you can move on to the individual endpoint pages to read and update data from your Zelt account.
Quick test: verify your token works
Once you have your access token, run this before building anything else:
curl -X GET "https://go.zelt.app/apiv2/partner/users" \
-H "Authorization: Bearer <your_access_token>"
200 OKwith a JSON array — your token is valid and has theuser:read:allscope.401 Unauthorized— token missing, malformed, or expired (see Common Errors).403 Forbidden— token is valid but your app is missing theuser:read:allscope.
Add ?includeTerminated=true to also return terminated users.
Try it in Postman or Bruno
Ready-made collections for the three calls you need to get started:
- Exchange authorization code for tokens —
POST /oauth/authorize/token,grant_type=authorization_code - Refresh the token pair —
POST /oauth/authorize/token,grant_type=refresh_token - List users —
GET /partner/users(a token test)
Downloads
- Postman collection (
.json, Collection v2.1) — Import → File. Requests 1 and 2 save the returnedaccessToken/refreshTokenback into the collection variables automatically. - Bruno collection (
.yaml) — Import Collection. Copy the tokens from response 1 or 2 into youraccessToken/refreshTokenvariables before running request 3.
Variables to fill in
| Variable | Where it comes from |
|---|---|
baseUrl | https://go.zelt.app/apiv2 (pre-filled) |
clientId / clientSecret | Your app in Zelt — see Create an app |
authorizationCode | The code on your redirect URI after you authorise the app. Single use, expires in 3 minutes — grab a fresh one right before running request 1. |
redirectUri | Only if your app was configured with one; it must match exactly. (Postman: enable the disabled redirect_uri field. Bruno: add it to the form body.) |
accessToken / refreshToken | The token pair returned by request 1 or 2. Use the newest pair before running request 3. |
The Authorization: Basic header on requests 1 and 2 is base64(clientId:clientSecret) — both
tools build it from the Basic-auth fields, you don't encode anything yourself.
The raw requests, for reference
1 — Authorization code → token pair
curl -X POST "https://go.zelt.app/apiv2/oauth/authorize/token" \
-u "CLIENT_ID:CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE"
# -d "redirect_uri=YOUR_REDIRECT_URI" # only if your app has one configured
2 — Refresh token → new token pair
curl -X POST "https://go.zelt.app/apiv2/oauth/authorize/token" \
-u "CLIENT_ID:CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=REFRESH_TOKEN"
Both return:
{ "access_token": "eyJhbGciOi...", "refresh_token": "eyJhbGciOi..." }
The access token is valid for 1 hour; the refresh token for 90 days. Each refresh
rotates the refresh token — always store the newest pair.
3 — Authenticated call
curl -X GET "https://go.zelt.app/apiv2/partner/users" \
-H "Authorization: Bearer ACCESS_TOKEN"
Common errors
| HTTP status | Likely cause | Fix |
|---|---|---|
401 Unauthorized | Token missing, expired, or malformed | Check the Authorization: Bearer <token> header format; re-generate token if expired |
403 Forbidden | Token is valid but lacks the required scope | Add the needed scope to your app and regenerate the token |
200 OK with empty results | Token is valid, but no scopes are assigned | Go to the Permissions page and assign scopes before generating the token |
400 Bad Request | Malformed request body | Check JSON formatting and required fields for that endpoint |