# Rules for every call These rules apply to every request in this guide. ## Base URL The base URL is `https://api.usehearsay.com`. All paths in this guide are relative to it. ## Headers on authenticated calls | Header | Value | |---|---| | `Authorization` | `Bearer ` (see "Step 1") | | `organization` | The id of the organization you are acting in | The sign-in routes need no token: register, login, refresh, the email-availability check and the two password-reset routes. Every other route needs the `Authorization` header. Almost every case, extraction-code, conversation and export route requires the `organization` header. If it is missing or wrong, the call fails even with a valid token. Each endpoint in the reference lists the header when it needs it. ## Response envelope Every success response is wrapped: - `data`: the actual result. - `statusCode`: the HTTP status. - `timestamp`: the time of the response. Always read the result from `data`. Treat any 2xx status as success: most creates return 201, and so do some updates. ## Lists and paging List routes accept `page` and `perPage` (or `skip` and `limit`), plus `sortBy` and `sortOrder`. The default is page 1 with 10 rows per page. A list response has one more level: `data` holds a page object, and the rows are in `data.data`. The page object also carries `total`, `totalPages`, `nextPage` and `previousPage`. To read everything, keep requesting pages until `nextPage` is `null`. Do not assume one page holds every row. If the order matters, send `sortBy` and `sortOrder` yourself instead of relying on the defaults. ## Errors An error response has `statusCode`, `timestamp`, `path` and `message`. `message` can be a string, or an object with a machine-readable `code`. When a code is present, branch on the code, not on the message text. ## Rate limits The API allows about 200 requests per minute. Some auth routes have lower limits; for example, the email-availability check allows 10 per minute. On HTTP 429, wait and retry with backoff. Do not retry in a tight loop. ## Ids Every id (case, extraction code, export, device, message, tag, file) is a 24-character hex string. Store the ids the API returns; never build or guess them. The one exception is the extraction code's `code`, the short value the custodian types in (for example `K7Q2-9XPL`). Routes that take `{extractionCode}` expect that code value, not an id. Where to find each id: | You need | Where it is | |---|---| | Organization id | `data.userProfile.userOrganizations[].organization.id` (login or register) | | Case id | `data.case.id` (create case); `data.data[].case.id` (list cases) | | Extraction code | `data.code` for the code value, `data.id` for its id (create code) | | Device id | `data.data[].dataSources[].sourceId` on iOS and Android rows (data-status-v2) | | Conversation id | `data.data[].id` (`GET /conversation/search`) | | Message id | `data.data[].id` (`GET /conversation/search-entries` and the message searches) | | Tag id | `data.data[].id` (`GET /case/tags/{caseId}`) | | Export id | `data.id` (start export); `data.data[].id` (list exports) | | File id | `file.id` on a completed export | ## Dates Send dates as ISO 8601, for example `2026-11-30T00:00:00.000Z`. ## Example An authenticated request: ```sh curl "https://api.usehearsay.com/case?page=1&sortBy=updatedAt&sortOrder=desc" \ -H "Authorization: Bearer $TOKEN" \ -H "organization: $ORG_ID" ``` A single result: ```json { "data": { "...": "the result" }, "statusCode": 200, "timestamp": "2026-01-15T10:15:00.000Z" } ``` A list result. The rows are in `data.data`: ```json { "data": { "data": [{ "...": "one row" }], "page": 1, "perPage": 10, "total": 42, "totalPages": 5, "nextPage": 2, "previousPage": null }, "statusCode": 200, "timestamp": "2026-01-15T10:15:00.000Z" } ```