skyfleetdocs

Errors API

Send your app's errors to Skyfleet. Each new one becomes an issue, with an agent on it.

POST /api/v1/signals
Authorization: Bearer sig_…
Content-Type: application/json

You'll find the token on the source's page under Integrations: App errors, Better Stack, ClickStack or Cloudflare. Each page makes its own tokens, and the token says which tool is calling. It works from the browser too.

Body

FieldType
servicestring, up to 60Required. Which app, like api or worker
messagestring, up to 4000Required. The error message
stackstring, up to 50,000The stack trace. Used for grouping
fingerprintstring, up to 200Your own grouping key
kindstringerror, the default and only kind
statusstringfiring, the default, raises the issue. Anything else, like resolved, is accepted and ignored

Better Stack and Cloudflare tokens take those tools' own webhook bodies instead, so they need no template: a Better Stack incident becomes one issue per incident (resolves and comments are ignored), and a Cloudflare health check one issue per check (going healthy is ignored, and so is Cloudflare's test message). Cloudflare can't set an Authorization header, so Skyfleet also takes the token from cf-webhook-auth.

Response

{ "issue": "is_8f2kQ…", "agent": true }

You'll get a 202 back. agent is true if this error started a new agent.

StatusWhen
401Unknown token
400A kind other than error, or a missing field
413Body over 256 KB

Grouping

Skyfleet groups repeats of the same error into one issue. By default it looks at the service, the error type and the first line of the stack trace that's in your own code, ignoring line numbers, so the same bug still groups after a new release. Send your own fingerprint if you'd rather group them differently.

Only a brand-new issue, or a resolved one that comes back, starts an agent. Ignored issues just keep counting.

Example

process.on('uncaughtException', (err) => {
  if (!process.env.SIGNALS_TOKEN) return
  fetch(process.env.SIGNALS_URL!, {
    method: 'POST',
    headers: { authorization: `Bearer ${process.env.SIGNALS_TOKEN}`, 'content-type': 'application/json' },
    body: JSON.stringify({ service: 'api', message: err.message, stack: err.stack }),
    signal: AbortSignal.timeout(2000),
  }).catch(() => {})
})

Send it and move on: use a short timeout, never let a failed report crash your app, and skip it when the token isn't set. Never send request bodies, cookies or your users' data.

On this page