Search the API requests, Auth, REST server, Postgres and Edge Function logs of a project, kept 7 days on Free up to 90 days on Enterprise.
| Limit | Free | Pro | Scale | Enterprise |
|---|---|---|---|---|
| Log retention | 7 days | 30 days | 60 days | 90 days |
Open your project and choose Logs. Every project's logs are collected about once a minute and kept for your plan's log retention: 7 days on Free, 30 on Pro, 60 on Scale and 90 on Enterprise.
#Sources
| Source | What it has |
|---|---|
| API requests | Every request to your project URL: time, method, path with the query, status, response time, size, client IP and user agent. Query strings that carry an API key, a token, a password or a code are replaced by [redacted]. |
| Auth | The Auth service: sign-ins, sign-ups, token refreshes, e-mails sent, errors. |
| REST server | The server behind /rest/v1: start-up, schema reloads and errors. |
| Postgres | Your database's errors and warnings, and schema changes (DDL). |
| Edge Functions | What your functions write with console.log, console.warn and console.error, start-up errors and limit stops. |
#Search
- Search: every word must appear in the line (any field); put a phrase in quotes. Not case-sensitive.
- Time: from the last 15 minutes up to your plan's retention. Lines are newest first; Load older continues below the last one.
- Level: errors only, warnings and errors, or everything. Status (API requests): 2xx to 5xx.
- Live refreshes every 5 seconds. Click a line for all its fields.
A search reads at most 72 hours or about 100 MB of logs at a time. When it stops before finding anything, Search older continues from there.
#From the API
curl "https://stitchdb.com/platform/v1/projects/<ref>/logs?source=api&status=5xx&since=2026-10-25T00:00:00Z" \
-H "Authorization: Bearer $STITCHDB_TOKEN"| Parameter | Meaning |
|---|---|
source | api, auth, rest, postgres or functions |
since, until | ISO date and time (default: your plan's retention, now) |
q, level, status | The filters above (level: error, warn, info; status: 404 or 4xx) |
limit | Lines per page, up to 1,000 (default 100) |
cursor | The next value of the previous page |
The answer has lines (each with t time, l level, m message and the source's fields), next (null on the last page) and retention_days. Any team member can read logs; access tokens need the projects:read scope. AI tools read them with get_logs (MCP).
#Log queries
To count, group and measure log lines instead of reading them, send a log query. It looks like SQL but never runs on a database: StitchDB reads it with a strict grammar and evaluates it over the log store. Log queries are available from the API, and to AI tools as query_logs.
curl -G "https://stitchdb.com/platform/v1/projects/<ref>/logs/query" \
-H "Authorization: Bearer $STITCHDB_ACCESS_TOKEN" \
--data-urlencode "query=SELECT status, count(*) AS n, p95(ms) FROM api WHERE status >= 500 GROUP BY status ORDER BY n DESC LIMIT 20" \
--data-urlencode "since=6h"You can also POST the same path with { "query": "SELECT …", "since": "…", "until": "…" }. More examples:
-- Slowest paths in the last hour
SELECT path, count(*), p95(ms), max(ms) FROM api GROUP BY path ORDER BY p95(ms) DESC LIMIT 10
-- 5xx per minute, for a chart
SELECT minute, count(*) FROM api WHERE status_class = '5xx' GROUP BY minute ORDER BY minute
-- Function errors by function
SELECT function, count(*) FROM functions WHERE l >= 'error' GROUP BY function
-- Distinct client IPs that failed to sign in
SELECT count(distinct ip) FROM api WHERE path LIKE '/auth/v1/token%' AND status >= 400| Part | What you can use |
|---|---|
SELECT | Fields, *, and the aggregates count(*), count(f), count(distinct f), sum, avg, min, max, p50, p90, p95, p99. Name a column with AS; otherwise it is called count, p95_ms and so on. |
FROM | api, auth, rest, postgres or functions |
WHERE | = != < <= > >=, IN (…), NOT IN, LIKE and ILIKE (% any text, _ one character), IS [NOT] NULL, AND, OR, NOT and parentheses. Strings go in single quotes. |
GROUP BY, ORDER BY, LIMIT | Group by any field; order by a field, a column name or an aggregate, ASC or DESC; at most 1,000 rows (default 100). |
| Source | Fields |
|---|---|
| Every source | t (time), l (level: debug < info < warn < error, so l >= 'warn' works), m (message), minute and hour (the time cut to the minute or hour, for time buckets) |
api | method, path, status, status_class (for example '5xx'), ms, bytes, ip, ua, id |
auth | method, path, status, status_class, component, action, request_id, error_code, event |
postgres | severity, user, pid |
functions | function, version, kind, execution_id |
rest | Only the common fields |
since and until take an ISO time or a duration such as 15m or 6h. The default is the last hour. One query covers at most 24 hours, within your plan's retention; run several queries for longer periods. There are no joins, subqueries or other functions. A query is at most 4,000 characters.
The answer has columns, rows, the since and until it used, and scanned (hours, lines and bytes read). A query reads at most 256 MB or 2 million lines and runs at most 25 seconds. Past that, the answer has partial: true and counted_from, the time from which lines were counted; narrow the time range to get a full answer. When other log queries are running, you get 429 with Retry-After: 5. Access tokens need the projects:read scope and share the logs rate limit (a burst of 30, then 1 request a second).
To send these logs to Datadog, Loki or your own endpoint as well, add a log drain.
#How logs are stored
Lines are kept in EU object storage, encrypted (AES-256), in hourly files per project and source. The current hour is searchable within about a minute; a project that writes more than 50,000 lines of one source in a minute keeps the first 50,000 and a note of how many were left out.