Skip to content
Developers

Requests, errors and limits

Base URL, response format, error codes, pagination, idempotency, rate limits and timestamp formats shared by every endpoint.

Every endpoint follows the same conventions. Read this page once, then use the reference pages for the details of each area. All examples assume your key is in the HIVE_API_KEY environment variable; see Authentication and API keys.

#Base URL and requests

All paths are served under one base URL, over HTTPS only:

Base URL
https://app.hive3.tech/api/v1
  • Send request bodies as a JSON object with Content-Type: application/json. An array or any other JSON value returns 400 invalid_request.
  • Send filters and pagination as query parameters.
  • Identify the acting account only through the key. A request never needs, and cannot supply, a user ID as its authority.
  • Request bodies have size limits, from 16 KiB for small updates up to 256 KiB for courses and content. A larger body returns 413 with the code invalid_request.
  • The API is meant to be called from servers and scripts. Browsers on other websites are not allowed to call it, and a key placed in front-end code is exposed to every visitor.

#Response format

A successful response is a JSON object with a data field. List endpoints add a page object.

One object
{ "data": { "id": "event_123", "title": "Portfolio night" } }
A list
{
  "data": [{ "id": "event_123", "title": "Portfolio night" }],
  "page": { "nextCursor": "1793126400000", "hasMore": true }
}

Creates normally return 201; reads and updates return 200. Optional fields that are not set may be null or omitted; do not rely on a field being present unless the reference marks it as always returned. Some field names use the older words person and community where this documentation says account. Both are account IDs.

#Errors

Every response outside the 2xx range has the same shape:

Error response
{
  "error": {
    "code": "insufficient_scope",
    "message": "API key does not include the required scope",
    "requiredScopes": ["account:read"]
  }
}

Branch on code, which is stable. message is meant for people and can change. requiredScopes appears only on insufficient_scope errors.

StatusCodeMeaning
400invalid_requestThe JSON body or query parameters are malformed, or a value failed validation. The message names the problem. Also used for capacity limits, such as enrolling in a full event.
401missing_authorizationThe Authorization header is absent.
401malformed_authorizationThe header is not Authorization: Bearer <api key>.
401invalid_api_keyThe key is unknown, revoked or expired, or its account is unavailable or scheduled for deletion.
403insufficient_scopeThe key is valid but lacks the scope for this route.
403plan_requiredThe key owner's account is below Honey Bee. The key is kept and works again after an upgrade.
403forbiddenThe key has the scope, but the account lacks the live role, ownership or plan the operation needs.
404not_foundThe item does not exist, or is not visible to the key owner.
409conflictA state conflict, such as reusing an idempotency key with a different request, or editing an event that has started.
413invalid_requestThe request body is larger than the route allows.
429rate_limitedA rate limit was reached. See Rate limits.
500server_errorSomething unexpected failed on Hive3's side. Retry later; if it persists, contact support.

A 404 is also returned when you ask for something you are not allowed to see, so that the API does not reveal whether it exists.

#Pagination

List endpoints accept limit and cursor unless the reference says otherwise.

ParameterNotes
limitPage size. Resource lists default to 25 and allow up to 100; a larger value is lowered to the maximum. A zero, negative or non-numeric value returns 400 invalid_request on resource lists. Search allows 1 to 50 (default 20).
cursorThe page.nextCursor value from the previous page. Treat it as opaque: store and return it, never build or parse it.

Lists are newest first and leave out archived items. When page.hasMore is true, pass page.nextCursor as cursor to continue; nextCursor is null on the last page. Walking nextCursor until hasMore is false visits the whole set.

Two exceptions: notification lists use limit, offset and unreadOnly (Notifications), and several lists return a plain data array with no page object, capped as follows: event participants, course and quest enrollments, quest evidence and job applications (200 each), community applications (100) and members (200), plus wallets, linked communities and notification mutes. Notifications return { notifications, hasMore, total, unreadCount } inside data.

bash
curl "https://app.hive3.tech/api/v1/events?limit=50&cursor=1793126400000" \
  -H "Authorization: Bearer $HIVE_API_KEY"

#Idempotency

Send an Idempotency-Key header on a create request so you can retry it after a timeout or dropped connection without creating a duplicate. It is read on these routes:

  • POST to /posts, /events, /courses, /content, /quests and /jobs
  • POST /broadcasts
  • POST /ai-assistant/documents
Create an event safely
curl https://app.hive3.tech/api/v1/events \
  -H "Authorization: Bearer $HIVE_API_KEY" \
  -H "Idempotency-Key: portfolio-night-2026-11" \
  -H "Content-Type: application/json" \
  -d '{"title":"Portfolio night","description":"Bring two projects"}'
  • Choose a unique value per intended action, such as a UUID or your own record ID. Keys are limited to 128 characters; longer values are cut.
  • Keys are scoped to your account and remembered for 48 hours.
  • A repeat with the same key, method, path and body returns the first response again, with the same status, and creates nothing new.
  • A repeat with the same key but a different body or path returns 409 conflict with Idempotency key was already used with a different request.
  • Only successful creates are remembered. If the first attempt failed, retrying with the same key runs it again.
  • Other write routes ignore the header. Where an action is naturally repeatable, such as awarding a credential to someone who already has it, the reference says so.

#Rate limits

Limits protect the service and use fixed windows that start on the clock minute, hour or day, so a count resets at the next boundary rather than a fixed time after your first request.

  • Account budget. All keys of one account share 600 requests per minute. Every request counts, including requests that fail with a missing scope.
  • Route budgets. Writes and expensive reads also have their own budget per account, summarized below. Budgets for creating and changing resources are kept separately for each kind (events, courses and so on) and for each workflow area.
AreaBudget
Create resource60 per minute per kind, plus per day: posts 100, events 20, courses 10, content 50, quests 30, jobs 20
Update / archive resource120 / 60 per minute per kind
Create comment60 per minute and 500 per day
Update or delete a comment90 per minute each
Like a post or comment30 per minute each
Workflow actions (enroll, apply, evidence)60 per minute for new actions, 120 per minute for decisions, per area
RSVP changes10 per minute and 100 per day, shared with the app
Membership join or apply / leave20 / 30 per minute
Application review, role change, member removal120 per minute each
Community access change30 per minute
Profile update, builders, preferences60 per minute each; profile access 30
Upload URLs60 per minute and 1,000 per day
Data export2 per hour
Notificationsmark read 240, delete 120, mutes 60, mark all read 30 per minute
Search60 per minute
Broadcastswrites 30 per minute; test 10 per hour; send 10 per hour
Ticketsupdates 60 per minute
AI assistantsaving the assistant, upload URLs and attaching documents 30 per minute; deleting a document 60
Credential awards30 requests per minute and 500 people per day, shared with the app

When a limit is reached the API returns 429 with the code rate_limited. Route budgets return Retry-After (seconds to wait), except on post likes, comment edits, deletes and likes, and the notification write routes. The 600-per-minute account budget also has no Retry-After. Budgets shared with the app (RSVP changes, credential awards, quest evidence) do return it. Build your client to handle both:

  1. If Retry-After is present, wait at least that many seconds.
  2. If it is absent, wait for the next clock minute and add random jitter, then retry with exponential backoff.
  3. Spread bulk work over time instead of sending it in a burst, and retry only requests that are safe to repeat (reads, or creates sent with an Idempotency-Key).

A few limits return 400 invalid_request with a plain message instead of 429: the per-day and per-item budgets behind post and comment likes, the shared profile builder save budget, the daily data-export limit, and the AI assistant document attach limits. Plan and cadence rules from the app, such as how often a plan may send broadcasts, are reported as 400 or 403 the same way. Read error.message and do not retry those automatically. Budgets are counted against the key owner's account, including when the key acts on a managed account.

#Timestamps

Timestamps you send are ISO 8601 strings that include an offset, for example 2030-01-01T10:00:00.000Z or 2030-01-01T12:00:00+02:00. A value without Z or an offset is rejected rather than guessed from a time zone.

Timestamps in responses use two formats, depending on the object:

ObjectFormatExample
Posts, events, courses, content, quests and jobs: createdAt, updatedAt, archivedAtUnix time in milliseconds (number)1793126400000
Comments, workflow rows, notifications, applications, broadcasts, tickets, AI assistant, credentialsISO 8601 in UTC (string)"2026-10-27T18:00:00.000Z"