This is the wire format the observability module ingests. It is deliberately small and fully documented so that a language without a first-party SDK is a copy-paste away rather than a support ticket.
The canonical definition lives in packages/core/src/observe/envelope.ts. This page describes exactly that schema.
Only events is required. environment, release, releaseCommit and platform at the envelope level are defaults applied to any event that omits them — so a batching client sends them once.
Three shorthand forms are accepted, for the smallest possible integration:
jsonc
{ "events": [ { … } ] } // canonical[ { … }, { … } ] // a bare array of events{ "message": "boom" } // a single bare event
Every key is normalized, so event_id, release_commit, in_app and context_line parse identically to their camelCase spellings. line_no and line normalize to lineno; col_no and column to colno; abs_path to filename. Write idiomatic Python or Go without a translation layer.
The keys insidetags, extra, contexts, data and headers are your data, not protocol, and are preserved verbatim.
Defaults to receipt time. Rejected if more than 7 days from now — a device with a wrong clock would otherwise pin the issue to 2044 and float it to the top of every list.
type
error | message
Inferred: error when exception is present, else message.
level
fatal | error | warning | info | debug
Defaults to error for exceptions, info for messages. Below the project’s floor ⇒ dropped.
platform
javascript, node, python, dotnet, go, ruby, java, php, rust, other
Display only.
message
string
Required if there’s no exception.
transaction
string
Route, job or component name — e.g. POST /checkout. Used as the culprit when no frame is in-app, and as the grouping key for stackless events.
environment
string
e.g. production, staging.
release
string
Must match what you upload source maps under.
releaseCommit
string
The commit this build came from. This is what points the root-cause agent at the right code.
serverName
string
Instance/host identifier.
exception
object
See below.
breadcrumbs
array
Up to 200, oldest → newest.
tags
{string: string}
Filterable key/values.
contexts
object
Free-form: browser, os, runtime, device.
extra
object
Anything else.
user
object
id, email, username, ipAddress. Hashed server-side into a counting key.
This is the one place inline differs from what you may expect. Sentry orders frames oldest-first, with the crash at the bottom. inline orders them newest first: frames[0] is where the error was thrown. Every reader — human or model — wants the crash site first, and it’s also the order every JS engine already produces.
Field
Type
Notes
filename
string
Absolute path or URL.
function
string
Function or method name.
module
string
Logical module, if your runtime has one.
lineno, colno
number
1-indexed line; column is needed for accurate source-map lookup on minified bundles.
inApp
boolean
Set this. It decides grouping and what the AI reads first. true = your code, false = dependency/runtime. Inferred if omitted (paths containing node_modules, .next, node:internal etc. are treated as vendor).
contextLine
string
The source line, if your runtime can read it.
preContext, postContext
string[]
Up to 10 lines either side.
Server runtimes can usually fill in the context lines directly; for minified browser code inline recovers them from your uploaded source maps.
Ordered oldest → newest, ending at the error. In practice this is the fastest route to a reproduction — the culprit is more often the failed request two rows up than the frame that happened to throw.
POST /api/observe/artifacts?release=<version>&name=<url-path>&commitSha=<sha>&environment=<env>Authorization: Bearer <write key>Content-Type: application/json<the raw .map file as the body>
Metadata in the query string, raw bytes as the body — so curl --data-binary @file works and no multipart parsing is needed anywhere.
name is the URL path of the bundle (not the map), by convention prefixed with ~: ~/_next/static/chunks/page-ab12.js. inline reduces it to a match key the same way it reduces incoming stack-frame URLs, which is how the two meet.
Reported this way, the issue groups on KeyError + submit/handle, shows the breadcrumb that explains it, counts one affected user — and if the project is linked to a repo, the root-cause agent opens app/claims.py at commit 9f2c1ab7d4e and reads line 88.