GraphJSON uses HTTP status codes plus a JSON or text response body. Handle the status first; error body wording can evolve.
Status codes#
| Status | Meaning | Recommended action |
|---|---|---|
2xx |
Request succeeded | Continue |
400 |
Invalid method, key, payload, timestamp, range, filter, or query | Fix the request; do not retry unchanged |
429 |
Ingestion requests are arriving too quickly | Retry with exponential backoff and jitter |
500 |
Internal ingestion failure | Retry a bounded number of times |
Some data and visualization failures are surfaced as 400 even when the underlying message is not a field-level validation error. Record the redacted body for diagnosis.
Error bodies#
Most validation errors look like:
{
"error": "Invalid API KEY"
}
Rate limiting can return plain text:
Too Many Requests
Use a parser that tolerates both:
async function graphJSONRequest(url, payload) {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(10_000)
});
const text = await response.text();
let body;
try {
body = text ? JSON.parse(text) : null;
} catch {
body = text;
}
if (!response.ok) {
const message =
typeof body === "object" && body?.error ? body.error : String(body);
throw new Error(`GraphJSON ${response.status}: ${message}`);
}
return body;
}
Ingestion limits#
| Limit | Value |
|---|---|
| Event payload | 10,000 serialized characters |
| Single logging request | 1 event |
| Bulk logging request | 50 events |
| Ingestion requests | 40 per second per workspace |
| Timestamp | Whole Unix seconds |
In bulk requests, jsons and timestamps must be non-empty arrays of equal length.
Query limits#
SQL query results are wrapped with an outer limit of 2,000 rows. Mutation statements are blocked.
Read traffic is expected to remain proportionate to stored event volume. GraphJSON may throttle sustained, unusually high rates of unique read queries. Embedded charts use caching, so repeated views of the same configuration are much less expensive than many unique configurations.
For capacity planning beyond ordinary interactive analytics, contact hi@graphjson.com.
Retry policy#
Retry:
- network failures
- timeouts
429500
Do not automatically retry an unchanged 400.
A bounded exponential schedule:
attempt 1: 250–500 ms
attempt 2: 500–1,000 ms
attempt 3: 1–2 s
attempt 4: 2–4 s
Add random jitter, respect an overall deadline, and cap the number of attempts.
Delivery semantics#
Logging endpoints do not expose an idempotency-key mechanism. A network failure can leave the client unsure whether an event was accepted.
For events that must be reconciled:
- include a stable source
event_id - retain failed jobs in a queue
- allow safe redelivery
- deduplicate by
event_idin SQL
This gives you explicit at-least-once behavior without pretending the transport guarantees exactly once.
Logging safely#
Record:
- endpoint name
- status
- request duration
- collection
- application-level event ID
- redacted error body
Do not record:
- API key
- full embed URLs
- complete customer payloads
- secrets contained in provider events
Support checklist#
When contacting support, include the approximate time and time zone, endpoint, collection, status, and redacted body. Never include the API key.