Reference
API keys
A Jestha API key is a long random string bound to one Jestha account. Your service stores it and sends it as a Bearer token on every API call. There's no token exchange — the key itself is the credential.
1. Generate a key
In your Jestha web app, open Settings → API access and click Generate new key. You'll set:
- A short label so you can recognize it later.
- One or more scopes.
- An optional expiry (never / 30 days / 90 days / 1 year / custom).
- An optional IP allowlist in CIDR notation.
The plaintext key is shown exactly onceon the next screen. Copy it and store it in your service's secret store (env var, vault, etc.) — there's no way to recover it later. If you lose it, revoke and generate a fresh one.
jes_live_a1b2c3d4e5f6g7h8…. The jes_live_ prefix identifies it as a Jestha API key so our server can route it through the right validator without a database lookup.2. Send it on every request
Add an Authorization header with the value Bearer <key>. That's the entire integration:
curl -X POST https://api.jestha.com/api/posts \
-H "Authorization: Bearer jes_live_..." \
-H "Content-Type: application/json" \
-d '{"content":"Hello from my service","visibility":"PUBLIC"}'const res = await fetch('https://api.jestha.com/api/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.JESTHA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: 'Hello from my service',
visibility: 'PUBLIC',
}),
});
if (!res.ok) {
throw new Error(`Jestha API ${res.status}: ${await res.text()}`);
}
const jes = await res.json();
console.log(jes.id);import os, requests
res = requests.post(
'https://api.jestha.com/api/posts',
headers={
'Authorization': f"Bearer {os.environ['JESTHA_API_KEY']}",
'Content-Type': 'application/json',
},
json={
'content': 'Hello from my service',
'visibility': 'PUBLIC',
},
timeout=10,
)
res.raise_for_status()
print(res.json()['id'])3. Posting on behalf of many users
A key is bound to one Jestha account. To post for multiple end users, sign each one up as a normal Jestha account (using the regular signup flow), then generate a key per account from inside their settings.
Each post lands under that customer's identity, with a small “via {label}” chip on the post for transparency.
4. Rotating a key
There's no built-in rotate endpoint — by design, since you should keep two keys live briefly so deploys aren't synchronized. To rotate:
- Generate a new key with the same scopes.
- Roll it out to your service.
- Once you've confirmed traffic is flowing, revoke the old key in settings.
5. Storing keys safely
- Treat keys like passwords — never commit them to git, never log them.
- Set an IP allowlist when possible.
- Pick an expiry that matches your operational hygiene.
- Revoke immediately if a key is exposed.
jes_live_a1b2****prefix. We hash keys at rest, so even a DB compromise doesn't leak any plaintext.6. Identify the account behind a key
Every key has implicit, no-scope-needed access to GET /api/auth/me— useful to confirm a key is valid and to store the account's stable id alongside the key in your data store.
curl https://api.jestha.com/api/auth/me \
-H "Authorization: Bearer jes_live_..."
# 200 OK
# { "id": "01HW...", "username": "poscos", "email": "...", "displayName": "...", ... }Use the returned id as your stable externalId. Usernames can be changed by the account owner; ids cannot.
7. Posting, editing, deleting, bouncing, commenting
Once authenticated, every content action lives under /api/posts. See Posts API for the full reference — request/response shapes for each verb, multipart upload, idempotency, error envelopes, and visibility values.
8. Handling errors
The auth layer returns these status codes on key problems:
| Status | Meaning |
|---|---|
| 401 | Invalid API key — wrong format or unknown hash. |
| 401 | API key revoked. |
| 401 | API key expired. |
| 403 | Request IP is not in this API key's allowlist. |
| 403 | Missing required scope (see Scopes). |
| 429 | Rate limit or daily quota exceeded — see retryAfter. |