Using the Public API v1 Audit Log APIs
This guide explains how to retrieve audit logs via the Public API using the search and query endpoints. The main idea: you use a timestamp once to find a starting point, then use log IDs for all actual retrieval and pagination.Why log IDs instead of timestamps?
- Search by time is supported only to get a starting point (the first log at or after a given time). The API returns one log and its ID.
- Fetching and pagination use that log ID (and then the ID of the last log in each page). We do not support “give me all logs between 10:00 and 10:15” by timestamp in a single call.
- Stable ordering — Logs are ordered by ID. IDs are unique and never change, so pagination is consistent even if many events share the same second.
- No gaps or duplicates — Using “last seen ID” as the cursor avoids skipping or duplicating logs when events are dense.
- Clear “next page” — The next request is always “logs after this ID,” which is unambiguous.
The two endpoints
| Purpose | Endpoint | You provide | You get |
|---|---|---|---|
| Find a starting log by time | GET /api/v1/logs/audit/search?time=<timestamp> | A timestamp (e.g. 10:00 AM) | One log object — the first log at or after that time. That log’s id is your cursor. |
| Fetch logs after a given log | GET /api/v1/logs/audit?from=<log_id>&take=<n> | A log ID (from) and how many to fetch (take, 1–1000) | Up to take logs whose ID is after from, in ascending order by ID. |
- Search returns a single log: the first one with
timestamp >=yourtime. The response body is{ "log": { "id": "...", "timestamp": "...", ... } }. You need thatlog.idfor the next step. - Query returns logs with ID strictly greater than
from. So the log you got from search is not included in the first query response — it is the first log in your time range; you add it to your results yourself, then use its ID to fetch the rest.
https://api.harvey.ai (or your environment’s base URL). Full paths are /api/v1/logs/audit/search and /api/v1/logs/audit. See developers.harvey.ai for the full API reference.
Example 1: “All logs since 10:00 AM”
Goal: at 10:15 AM, get every audit log from 10:00 AM onward.Step 1 — Get the first log and its ID (timestamp → ID)
- Call:
GET /api/v1/logs/audit/search?time=<10:00 AM in ISO 8601 or your API’s accepted format> - Response:
{ "log": { "id": "abc-123-...", "timestamp": "2025-03-11T10:00:00.000Z", ... } } - Keep this log — it is the first log in your range. Add it to your result set.
- Save
log.id(e.g.abc-123-...) — this is your cursor for the next request.
Step 2 — Fetch the next logs (ID-based)
- Call:
GET /api/v1/logs/audit?from=abc-123-...&take=1000 - Response:
{ "logs": [ ... ] }— up to 1000 logs whose ID is afterabc-123-....
Step 3 — Paginate if needed
- Each response contains at most
takelogs (here, 1000). You never get “more than 1000” in one response. - If you got exactly 1000 logs, there may be more. Take the last log in the array and use its
idas the newfrom:GET /api/v1/logs/audit?from=<last_log_id>&take=1000
- Repeat until a response has fewer than 1000 logs — then there are no more.
Example 2: “A 15-minute slice starting at 8:00 AM”
Goal: all logs from 8:00 AM to 8:15 AM. You still use search to turn “8:00 AM” into a starting log ID, then query by ID. The only extra part is stopping when logs go past 8:15 AM.Step 1 — Get the first log at or after 8:00 AM
- Call:
GET /api/v1/logs/audit/search?time=<8:00 AM> - Keep the returned log as the first log in your slice.
- Save
log.idfor the next request.
Step 2 — Fetch in pages and stop at the end time
- Call:
GET /api/v1/logs/audit?from=<saved_id>&take=1000 - For each log in
logs, check itstimestamp:- If
timestamp <= 8:15 AM→ include it in your 15-minute slice. - If
timestamp > 8:15 AM→ you’ve passed the end of the window; stop requesting more and (optionally) drop any later logs from this batch.
- If
- If you got 1000 logs and the last one is still before or at 8:15 AM, there may be more in that window. Use the last log’s
idasfromand call again. Repeat until you either get fewer than 1000 logs or you see a timestamp after 8:15 AM.
Summary
- Timestamps answer: “Where do I start?” (search) and “Where do I stop?” (your own end-time filter).
- Log IDs answer: “What’s the next page?” (query’s
fromand pagination). - Always include the log returned by search in your results; the first query call returns only logs after that log’s ID.
- Pagination: use the last log’s ID from each response as
fromfor the next request; when you get fewer thantakelogs, you’ve reached the end.