An event records that something happened in your product. Every event has a name and a channel; everything else is optional.
Send one event
POST https://api.logzuno.app/v1/log with an ingest key in the Authorization header:
curl -sS -X POST "${LOGZUNO_ENDPOINT:-https://api.logzuno.app/v1}/log" \
-H "Authorization: Bearer $LOGZUNO_API_KEY" \
-H "Content-Type: application/json" \
-w "\nHTTP %{http_code}\n" \
-d '{
"channel": "signups",
"event": "User signed up",
"user_id": "user-123",
"description": "A new user created an account",
"icon": "🎉",
"notify": true,
"tags": { "plan": "growth", "source": "website" }
}'| Field | Required | What it is |
|---|---|---|
channel | Yes | Where the event belongs: signups, billing, errors. Created the first time it is used |
event | Yes | What happened, in words: User signed up |
user_id | No | Your ID for the person who did it. Links the event to a user |
group_id | No | The account or company it belongs to. See groups |
description | No | One line shown under the event in the feed |
icon | No | One emoji shown beside it |
notify | No | true sends a browser push to members who opted in |
tags | No | Properties: a flat object of strings, numbers, booleans or null (properties works too) |
timestamp | No | Unix seconds, if the event happened earlier; defaults to now |
insert_id | No | A UUID. The same insert_id is stored once, so retries are safe |
LogZuno answers 202 Accepted with the event's insert_id. The event is in the live feed and in charts within seconds.
Send up to 100 at once
POST /v1/batch takes an events list of up to 100 events in the same shape. A batch counts as one request against the limit of 5 requests a minute per project, so batching lets one project send up to 500 events a minute.
curl -sS -X POST "${LOGZUNO_ENDPOINT:-https://api.logzuno.app/v1}/batch" \
-H "Authorization: Bearer $LOGZUNO_API_KEY" \
-H "Content-Type: application/json" \
-w "\nHTTP %{http_code}\n" \
-d '{
"events": [
{ "channel": "billing", "event": "Invoice created", "user_id": "user-123", "tags": { "amount": 320 } },
{ "channel": "billing", "event": "Payment received", "user_id": "user-123", "notify": true, "tags": { "amount": 320 } }
]
}'A batch is all or nothing: if any event is invalid, LogZuno rejects the whole request with 422 and names the failing fields (events.1.channel), so you can fix it and resend the batch without creating duplicates.
Retry on 429
When a project goes over its request limit, LogZuno answers 429 Too Many Requests with a Retry-After header in seconds. Wait that long and resend:
// Node.js 18+: send up to 100 events per request, and retry when LogZuno
// answers 429 (rate limit) after the number of seconds in Retry-After.
const endpoint = process.env.LOGZUNO_ENDPOINT ?? "https://api.logzuno.app/v1";
async function sendBatch(events, attempt = 1) {
const response = await fetch(`${endpoint}/batch`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LOGZUNO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ events }),
});
if (response.status === 429 && attempt < 5) {
const seconds = Number(response.headers.get("Retry-After") ?? 60);
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
return sendBatch(events, attempt + 1);
}
return { status: response.status, body: await response.json() };
}
const events = [
{ channel: "product", event: "Report exported", user_id: "user-123", tags: { format: "csv" } },
{ channel: "product", event: "Report shared", user_id: "user-123", tags: { with: "team" } },
];
console.log(await sendBatch(events));When the organisation has used its monthly allowance, LogZuno also answers 429, with "reason": "quota_exceeded". Waiting won't help that one: upgrade the plan or wait for the next billing period.
Naming events well
- Use past-tense, human names:
Invoice paid, notinvoice_paid_v2. They are what your team reads in the feed and in alerts. - Put variations in properties, not in the name:
Plan upgradedwith{ "from": "starter", "to": "growth" }, not one event name per plan. - Keep one channel per area of the product, so muting and filtering stay useful.
- Use
notifyfor what someone should act on now. A push for every page view trains people to ignore pushes.