Appearance
Projects
Create and manage log projects. Each project has its own ingest token, retention settings, and streams.
Base URL: https://app.krafter.dev/api/v1
List Projects
Retrieve all log projects.
GET /logs/projectsRequired scope: logs:read
Example Request
bash
curl https://app.krafter.dev/api/v1/logs/projects \
-H "Authorization: Bearer kr_live_abc123def456"Example Response
json
{
"data": [
{
"id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"name": "My App",
"description": "Production logs",
"retention_days": 30,
"daily_limit_mb": 500,
"ingest_token_prefix": "krl_live_kp7",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
},
{
"id": "b2c3d4e5-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"name": "Staging",
"description": "Staging environment logs",
"retention_days": 7,
"daily_limit_mb": 100,
"ingest_token_prefix": "krl_live_aab",
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
}
]
}Create Project
Create a new log project. A unique ingest_token is generated automatically.
POST /logs/projectsRequired scope: logs:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the project. Must be unique within the team. |
description | string | No | Optional description. |
retention_days | integer | No | Number of days to retain log entries. Range 1--90. Defaults to 7. |
daily_limit_mb | integer | No | Daily ingestion limit in megabytes. Must be greater than 0. Defaults to 500. |
Example Request
bash
curl -X POST https://app.krafter.dev/api/v1/logs/projects \
-H "Authorization: Bearer kr_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"name": "My App",
"description": "Production logs",
"retention_days": 30
}'Example Response
json
// 201 Created
{
"data": {
"id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"name": "My App",
"description": "Production logs",
"retention_days": 30,
"daily_limit_mb": 500,
"ingest_token_prefix": "krl_live_kp7",
"ingest_token": "krl_live_kp7tx2bm4qrs6vwy3jnh5zfd7acmeg2j",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
}TIP
Save the ingest_token from the response — it is returned only on creation and rotation. List, get, and update responses include ingest_token_prefix (the first 12 characters) for identification but never the full token. Your services will use the full token to send logs to the Ingest API.
Get Project
Retrieve details of a specific project.
GET /logs/projects/:idRequired scope: logs:read
Example Request
bash
curl https://app.krafter.dev/api/v1/logs/projects/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
-H "Authorization: Bearer kr_live_abc123def456"Example Response
json
{
"data": {
"id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"name": "My App",
"description": "Production logs",
"retention_days": 30,
"daily_limit_mb": 500,
"ingest_token_prefix": "krl_live_kp7",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
}Update Project
Update an existing project. Only provided fields are changed.
PUT /logs/projects/:idRequired scope: logs:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Display name for the project. Must remain unique within the team. |
description | string | No | Optional description. |
retention_days | integer | No | Number of days to retain log entries. Range 1--90. |
daily_limit_mb | integer | No | Daily ingestion limit in megabytes. Must be greater than 0. |
Example Request
bash
curl -X PUT https://app.krafter.dev/api/v1/logs/projects/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
-H "Authorization: Bearer kr_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"retention_days": 90,
"daily_limit_mb": 500
}'Example Response
json
{
"data": {
"id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"name": "My App",
"description": "Production logs",
"retention_days": 90,
"daily_limit_mb": 500,
"ingest_token_prefix": "krl_live_kp7",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-16T09:30:00Z"
}
}Delete Project
Permanently delete a project and all its log data, streams, and alerts.
DELETE /logs/projects/:idRequired scope: logs:write
Example Request
bash
curl -X DELETE https://app.krafter.dev/api/v1/logs/projects/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
-H "Authorization: Bearer kr_live_abc123def456"Example Response
// 204 No ContentRotate Ingest Token
Generate a new ingest token for a project. The old token is revoked immediately.
POST /logs/projects/:id/rotate_tokenRequired scope: logs:write
Example Request
bash
curl -X POST https://app.krafter.dev/api/v1/logs/projects/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/rotate_token \
-H "Authorization: Bearer kr_live_abc123def456"Example Response
json
{
"data": {
"id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"name": "My App",
"description": "Production logs",
"retention_days": 30,
"daily_limit_mb": 500,
"ingest_token_prefix": "krl_live_xn4",
"ingest_token": "krl_live_xn4w7bm2tk6qrs3vwy5jnh7zfdcameg2p",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-16T12:00:00Z"
}
}WARNING
After rotating, the old ingest token stops working immediately. Update all services that send logs to this project with the new token.
List Streams
List all streams that have been auto-discovered for a project. Streams are created automatically from the stream field in ingested log entries.
GET /logs/projects/:id/streamsRequired scope: logs:read
Example Request
bash
curl https://app.krafter.dev/api/v1/logs/projects/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/streams \
-H "Authorization: Bearer kr_live_abc123def456"Example Response
json
{
"data": [
{
"id": "c3d4e5f6-7a8b-9c0d-1e2f-3a4b5c6d7e8f",
"name": "backend",
"inserted_at": "2025-01-15T10:01:00Z"
},
{
"id": "d4e5f6a7-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
"name": "worker",
"inserted_at": "2025-01-15T10:02:00Z"
},
{
"id": "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b",
"name": "auth",
"inserted_at": "2025-01-15T10:03:00Z"
}
]
}Retention
Each project has a retention_days setting (range 1--90, default 7) that controls how long log entries are kept. A nightly cleanup worker deletes entries older than the configured value on a per-project basis.
Retention safety net
In addition to your project's retention_days (enforced nightly by the cleanup worker), the underlying ClickHouse log_entries table has a hard TTL of 90 days. Even if retention_days is misconfigured, the cleanup worker fails, or a project is left without a custom value, log entries older than 90 days are removed automatically by the storage engine. You cannot retain log entries beyond 90 days on the current Krafter platform — set retention_days to a value ≤ 90 and design downstream archival accordingly.
Daily Ingestion Limit
Each project carries a daily_limit_mb setting (default 500). When an ingest request is received, Krafter checks today's usage and rejects further entries with 429 Daily log ingestion limit exceeded once the threshold is reached.
What counts toward the limit
bytes_in for each accepted entry is computed from the payload string fields only — specifically message, stream, service, trace_id, span_id, and the JSON-encoded metadata object. HTTP framing, JSON encoding overhead (quotes, commas, brackets), the timestamp, and the level field are not counted. Treat daily_limit_mb as a soft cap on logical payload size, not as a wire-byte budget.
The counter resets at the start of each UTC day.
Limit is per-team in practice, not per-project
The daily_limit_mb value lives on each project, but the enforcement counter (bytes_in) is aggregated per team — Logs.daily_limit_exceeded?/2 looks up today's total bytes for the project's team and compares it against that single project's daily_limit_mb.
In practice this means:
- If a team has multiple projects, the lowest
daily_limit_mbacross those projects is what the team will hit first. - A second project on the same team with a higher limit will still see
429once the team-wide aggregate crosses the first project's threshold.
This mismatch between field semantics ("per-project limit") and enforcement ("per-team aggregate") is tracked as a bug in the logs truth-up plan and will be reconciled in a follow-up PR. Until then, set daily_limit_mb consistently across projects on the same team to avoid surprises.