vakaGitHub

Ingest protocol (v1)

SDKs send data to POST https://vaka.example.com/ingest/v1/batch. This page is the contract every SDK implements; any language can use it directly.

Authentication

Send the project's ingest key (starts with vk_) in the X-Vaka-Key header. Ingest keys are write-only and safe to embed in apps. For navigator.sendBeacon, which cannot set headers, use ?key=vk_... in the URL instead.

Optional: X-Vaka-Sdk: name/version on the single-kind endpoints below.

Request

POST /ingest/v1/batch
X-Vaka-Key: vk_...
Content-Type: application/json
Content-Encoding: gzip          (optional)

{
  "sdk": {"name": "vaka-android", "version": "0.1.0"},
  "items": [ {"type": "error", ...}, {"type": "session", ...}, {"type": "event", ...} ]
}

Response

202 Accepted with {"accepted": 3, "rejected": [{"index": 1, "error": "..."}]}. Invalid items are reported individually and never fail the whole batch. Other statuses:

Status Meaning SDK behaviour
400 Body is not JSON, or no item was valid Drop the batch, log the error message
401 Missing, unknown or revoked key Stop sending until the app restarts
413 Too many items Split the batch
429 / 503 Queue full or temporarily unavailable Retry with exponential backoff (max ~5 min)

Errors always come back as {"error": "human-readable explanation"}.

Common fields

Timestamps (timestamp, started) accept RFC 3339 strings ("2026-11-10T08:00:00.123Z"), unix seconds (float) or unix milliseconds. Missing timestamps default to the time of receipt.

release should be the app version as users see it ("2.3.1" or "2.3.1+45"), and it must match the release used when uploading debug files. environment defaults to production.

Error item

{
  "type": "error",
  "event_id": "1f0c7c4e-0b1a-4b7e-9e7a-0d7b5d3f1a2b",
  "timestamp": "2026-11-10T08:00:00.123Z",
  "platform": "android",
  "level": "error",
  "fatal": false,
  "handled": true,
  "release": "2.3.1",
  "environment": "production",
  "message": "optional free-text message (used when there is no exception)",
  "exceptions": [
    {
      "type": "java.lang.IllegalStateException",
      "value": "Cart is empty",
      "module": "com.example.cart",
      "stacktrace": [
        {"function": "checkout", "module": "com.example.cart.CartViewModel", "filename": "CartViewModel.kt", "lineno": 42, "in_app": true},
        {"function": "onClick", "module": "com.example.ui.CartFragment", "filename": "CartFragment.kt", "lineno": 88, "in_app": true}
      ]
    }
  ],
  "breadcrumbs": [
    {"timestamp": "2026-11-10T07:59:58Z", "category": "navigation", "message": "Cart", "level": "info", "data": {}}
  ],
  "tags": {"flavor": "free"},
  "contexts": {"app": {"build": "45"}, "runtime": {"name": "Android", "version": "15"}},
  "user": {"id": "user-123"},
  "anon_id": "random-install-id",
  "session_id": "uuid of the current session",
  "device": {"model": "Pixel 9", "os_name": "Android", "os_version": "15", "app_version": "2.3.1"},
  "url": "https://example.com/cart",
  "debug_images": [],
  "fingerprint": ["optional", "custom", "grouping", "key"]
}

Rules:

Native crashes (iOS, Rust, C/C++)

Send raw addresses plus the loaded images; the server symbolicates with uploaded debug files.

"exceptions": [{"type": "EXC_BAD_ACCESS", "value": "SIGSEGV at 0x0", "stacktrace": [
  {"instruction_addr": "0x0000000104a3c1f4", "in_app": true},
  {"instruction_addr": "0x0000000104a3b0e8"}
]}],
"debug_images": [
  {"type": "macho", "debug_id": "6a8e2b3c-1f0d-3e4a-9b8c-7d6e5f4a3b2c", "code_file": "/private/var/containers/.../MyApp",
   "image_addr": "0x0000000104a20000", "image_size": 1048576}
]

JVM / Android with R8

Send obfuscated class and method names as they appear (module = class, function = method, lineno). The server deobfuscates them with the mapping uploaded for the same release.

JavaScript

Send abs_path (the script URL), lineno and colno from the minified stack. The server applies the source map uploaded for that file and release.

Session item (release health)

{"type": "session", "session_id": "uuid", "status": "ok", "started": "...", "timestamp": "...",
 "duration_ms": 5400, "errors": 0, "release": "2.3.1", "environment": "production",
 "user_id": "optional", "anon_id": "random-install-id"}

Event item (analytics)

{"type": "event", "name": "pageview", "url": "https://example.com/pricing?utm_source=hn",
 "referrer": "https://news.ycombinator.com/", "props": {"plan": "pro"}}

Privacy guarantees