Check-in payload
The wire contract. Useful when you are writing a client by hand, or working out why an SDK's output is not producing what you expected.
Envelope
POST https://ingest.parsemend.com/api/{project_id}/envelope/
X-Sentry-Auth: Sentry sentry_key={public key}, sentry_version=7{} ← envelope header
{"type":"check_in"} ← item header
{"check_in_id":"...", ...} ← payloadNewline-separated. The envelope header may be empty. The item header needs only type; an optional integer length switches the payload from newline-delimited to length-prefixed.
An envelope may carry several items of mixed types. Check-ins are extracted by item type, so a single POST can carry a check-in and an event together.
Payload fields
| Field | Type | Notes |
|---|---|---|
check_in_id | string | Client-generated, unique per run. If absent a random one is assigned, which makes the two-phase pattern impossible |
monitor_slug | string | Identifies the monitor within the project. Required in practice |
status | string | in_progress, ok, or error |
duration | number | Seconds, float allowed. Stored and displayed as milliseconds |
release | string | Empty string is treated as absent |
environment | string | Empty string is treated as absent |
monitor_config | object | See below. Optional, and omitting it disables detection |
contexts | object | Accepted and ignored for check-ins |
Nothing here throws on bad input. A malformed field degrades to null rather than rejecting the check-in, which means a typo produces a monitor that quietly does less than you think rather than an error you can see. Check the panel after wiring up a new job.
monitor_config
| Field | Type | Notes |
|---|---|---|
schedule.type | string | crontab or interval |
schedule.value | string or number | Cron expression, or the interval count |
schedule.unit | string | Interval only: minute, hour, day, week, month |
timezone | string | tz database name. Defaults to UTC. Affects crontab only |
checkin_margin | int | Minutes of grace before missed. Defaults to 5 |
max_runtime | int | Minutes before an in_progress run times out. Defaults to 30 |
failure_issue_threshold | int | Accepted and ignored |
recovery_threshold | int | Accepted and ignored |
schedule.value is accepted as a JSON number for intervals, which is what both verified SDKs send, and coerced to a string internally.
unit: "year" is accepted by the Sentry SDKs and produces no next expected time here. See schedules.
Config updates merge, they never clear
Every non-null field in monitor_config overwrites the stored value; null and absent fields leave the stored value alone.
So a monitor that once received max_runtime: 120 keeps 120 forever, even after you delete the line from your code. To change it, send a new value. There is no way to reset a field back to the platform default from the SDK side.
Status semantics
| Status | Effect on the check-in row | Effect on the monitor |
|---|---|---|
in_progress | Created or updated; started_at set on creation | Status unchanged. Last check-in time updated |
ok | Updated to ok | Status becomes ok. Resolves open monitor issues if it was bad |
error | Updated to error | Status becomes error. Opens an issue on the transition |
| empty or unrecognised | Row keeps its previous status | Status unchanged |
timeout and missed are set by the platform, never sent by a client.
An in_progress check-in deliberately does not change the monitor's status. The badge in the panel keeps showing the outcome of the last completed run while the current one is in flight.
Identity and idempotency
| Object | Key |
|---|---|
| Monitor | (project_id, monitor_slug) |
| Check-in | (monitor_id, check_in_id) |
Both are upserts, which is what makes the two-phase pattern work: in_progress then ok with the same check_in_id updates one row rather than writing two.
It also makes retries safe. A client that posts the same terminal check-in twice updates the same row, and the issue pipeline fires on the transition into error, not on each post, so a retried POST does not double-report.
Slug is identity. Renaming a slug creates a new monitor and orphans the old one, which then goes missed on its next slot and stays that way. There is no rename and no delete in the panel, so pick slugs you can live with.
Timing recomputation
next_expected_at is recalculated on every check-in, from the time the check-in was processed:
crontab: the next moment the expression matches, in the monitor's timezone, stored as UTC.interval: processing time plus the interval.- No usable schedule: null, and the monitor is never swept.
The missed sweep advances it differently, from the slot that was missed rather than from the current time, so one issue event is produced per missed slot.
Limits
| Limit | Value |
|---|---|
| Rate limit | 300 requests per 60 seconds per project, by default |
| Max compressed envelope | 20 MiB |
| Max item size | 1 MiB |
The size caps are irrelevant to check-ins, which run to a few hundred bytes. The rate limit is shared with error and transaction traffic from the same project.
