Introduction
Introduction
Base URL
The Tailglow API is built on REST principles. We enforce HTTPS in every request to improve data security, integrity, and privacy. The API does not support HTTP.
All requests contain the following base URL:
https://api.tailglow.io Authentication
To authenticate with the Tailglow API, send your API key in the Authorization header using the Bearer scheme. An API key looks like tg_api_ followed by 70 characters.
Authorization: Bearer tg_api_1a2B3c4D5e6F7g8H9i0J... Authorization: Key <your key> is also accepted, as is sending the key on its own with no scheme. Keys issued before the tg_api_ prefix begin with sk_ and keep working indefinitely.
Filtering Data
When filtering data, you’ll create a query string that will be appended to the URL of your GET request. The query string will begin with a ? and contain key-value pairs separated by &.
Be careful when using "not" filters. They can result in a lot of data being returned. Tailglow uses a single canonical operator vocabulary across every filter surface. URL syntax is flat: ?<field>=<op>:<value>. The full list, per-type allowlists, and per-surface availability matrix live in the Filter Operators enum.
Strings
equals-?type=equals:expensenot_equals-?type=not_equals:expensestarts_with-?type=starts_with:expensenot_starts_with-?type=not_starts_with:expenseends_with-?type=ends_with:expensenot_ends_with-?type=not_ends_with:expensecontains-?type=contains:expensenot_contains-?type=not_contains:expensein-?type=in:expense,refundnot_in-?type=not_in:expense,refund
String operators compare case-insensitively, so ?type=equals:GET and ?type=equals:get include the same rows.
Numbers
equals-?value=equals:100not_equals-?value=not_equals:100gt(Greater Than) -?value=gt:100gte(Greater Than or Equal) -?value=gte:100lt(Less Than) -?value=lt:100lte(Less Than or Equal) -?value=lte:100between-?value=between:100,200in/not_in-?value=in:100,200
Pagination
Most list endpoints use cursor-based pagination. The first request omits the cursor; subsequent requests echo back the next_cursor (or prev_cursor) the previous response handed you.
Request parameters
limitnumberMaximum number of items to return per page. Defaults to25, max200.afterstringOpaque cursor from a previous response’spagination.next_cursor. Returns the rows after the pivot.beforestringOpaque cursor from a previous response’spagination.prev_cursor. Returns the rows before the pivot. Mutually exclusive withafter.sort"asc" \| "desc"Sort direction. Cursors are minted under one direction; reusing them under a different sort returns a400.
Response shape
The pagination object on every list response carries:
limitnumber: echoed from the request.countnumber: number of rows in this page (≤limit).offsetnumber: 0-indexed position of the first row across the full result set. Useoffset + 1for “Showing 21” labels.sort"asc" \| "desc": echoed sort direction.next_cursorstring \| null: cursor for the next page.nullmeans there are no more rows.prev_cursorstring \| null: cursor for the previous page.nullmeans you’re on the first page.totalnumber \| null: exact row count for database-backed lists and records.nullis returned only when the underlying feed cannot provide a total. For example, collection docs always returnnullbecause the underlying files aren’t enumerated.
Cursors are server-minted opaque tokens. Don’t construct them yourself; round-trip the values the API gave you.
Responses
All of our responses will follow a standard structure, regardless if it’s successful or not. Here is an example of the response object.
Successful Response Example
If you are listing data, the data key will be an array of objects and a pagination object will be present.
If you are retrieving, creating, or writing a single object, the data key will be an object.
If you are deleting an object, the data key will be null.
{
"message": "Data retrieved successfully",
"data": [],
"status": 200,
"error": null,
"pagination": {
"object": "pagination",
"limit": 10,
"count": 10,
"offset": 0,
"sort": "desc",
"next_cursor": "eyJ2IjoxLCJyZXNvdXJjZSI6...",
"prev_cursor": null,
"total": 42
},
"endpoint": "/v1/projects"
} Error Response Example
You’ll typically see error when request validations fail. The error key will contain an object with a code key and a properties key that will contain an array of objects with an id and message key. The id corresponds to the field that failed validation and the message will contain the error message.
{
"message": "The request is invalid",
"data": null,
"status": 400,
"error": {
"code": "request_invalid",
"properties": [
{
"id": "name",
"message": "Name is required"
}
]
},
"pagination": null,
"endpoint": "/v1/projects"
}