API Reference

Dump Triage API — v1

Upload a Windows crash or memory dump, get an AI-triaged report back — automatically, or escalated to a human engineer when the evidence calls for it. Built for enterprise IT, ISVs shipping crash-reporting integrations, and solo developers debugging one dump at a time.

Base URL https://api.performanceinsights.ai Format JSON over HTTPS Auth Bearer API key

1. Overview

Every dump goes through the same pipeline: upload → Tier 1 (fast automated triage) → Tier 2 (deep automated review, if Tier 1 isn't confident) → Tier 3 (human engineer, if the evidence still doesn't add up). Most dumps resolve automatically; you'll see that in the report's decision field either way.

Scope

V1 analyzes Windows user-mode (minidump) and kernel-mode (full/kernel memory) dumps. Linux dump support is tracked as a future addition, not yet available.

2. Authentication

Every request except signup and verification needs a bearer API key:

Authorization: Bearer dts_<your-key>

Keys are issued once, at signup verification (§5) — store it immediately, it isn't retrievable again. Keys aren't scoped per-user; one key represents one account/organization.

3. Tiers & Quotas

Self-serve accounts get a free, metered quota per rolling 30-day period. Uploading past your quota returns 429 until the period rolls over. There's no paid tier yet — if you need a higher limit, get in touch.

TierMonthly dumpsLargest dumpMonthly upload volumeWho it's for
solo12 GiB2 GiBAn individual developer debugging their own crashes.
isv108 GiB40 GiBA software vendor piping customer crash dumps through automated triage.
enterprise2516 GiB100 GiBAn internal IT/engineering team triaging a fleet's worth of dumps.

Re-uploading a dump you've already uploaded (identical bytes) is deduplicated and doesn't count against your quota.

4. Quickstart

# 1. Sign up (choose tier: solo | isv | enterprise)
curl -X POST https://api.performanceinsights.ai/api/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"org":"Acme Inc","contact":"Jane Dev","email":"jane@acme.example","tier":"solo"}'
# -> {"customer_id": "...", "status": "pending_verification"}

# 2. Click the link in the verification email, or verify directly:
curl -X POST https://api.performanceinsights.ai/api/v1/signup/verify \
  -H "Content-Type: application/json" \
  -d '{"token":""}'
# -> {"customer_id": "...", "api_key": "dts_..."}   <-- save this, shown once

# 3. Upload a dump
curl -X POST https://api.performanceinsights.ai/api/v1/dumps \
  -H "Authorization: Bearer dts_..." \
  -F "file=@crash.dmp"
# -> {"id": "...", "dump_type": "user_mode", "status": "uploaded", "job_state": "queued",
#     "size_bytes": 123456, "uploaded_at": "...", "download_url": "/api/v1/dumps/download?uri=...&token=..."}

# 4. Poll for the report
curl https://api.performanceinsights.ai/api/v1/dumps/<id>/report \
  -H "Authorization: Bearer dts_..."
# -> {"job_state": "delivered", "decision": "delivered", "reports": [...]}

5. Signup

POST/api/v1/signup

Body: {org, contact, email, tier}tier is one of solo, isv, enterprise. Returns 202 with {customer_id, status: "pending_verification"} and sends a verification email. Posting again with the same (unverified) email resends the link, at most once per 60 seconds (429 otherwise). An email that's already verified returns 409. Also rate-limited per source IP (a handful of signups per hour) — a 429 past that limit carries a Retry-After header.

POST/api/v1/signup/verify

Body: {token} (from the emailed link). Returns {customer_id, api_key} — the only time the plaintext key is shown. An invalid, already-used, or expired (24h) token returns 400. The emailed link opens a confirmation page; the key is only issued once you press its button, so a mail scanner fetching the link can't use up your token.

6. Dumps

POST/api/v1/dumps

Multipart upload, field name file. Dump type (user-mode vs kernel-mode) is detected from the file itself, not a parameter — recognized by magic bytes MDMP (user-mode minidump) or PAGE (kernel/full memory dump); anything else is the 422 below. Returns 201 with the dump record: {id, dump_type, status, size_bytes, uploaded_at, job_state, download_url}. 422 for an unrecognized format, 413 if the file is larger than your tier's per-dump size (or what's left of your monthly upload volume), or 429 if you're over quota (§3). Oversized uploads are cut off at the limit, not after the full transfer.

GET/api/v1/dumps

Lists your dumps, most recent first. Same shape as the upload response, one per dump.

GET/api/v1/dumps/{id}

Fetch one dump's status. Same shape as the upload response.

GET/api/v1/dumps/download?uri=&token=

Downloads the original file via a short-lived (1h) signed URL. Take uri/token straight from the download_url field on the dump record above — don't construct them yourself. An expired or tampered token returns 403.

7. Reports

GET/api/v1/dumps/{id}/report

Returns {dump_id, job_state, decision, reports}. decision is null while still processing, otherwise "delivered" (automated triage resolved it) or "escalated" (a human is on it). reports holds each tier's findings, confidence signals, and cost accounting as they complete.

8. Symbols

POST/api/v1/symbols

Multipart upload (file, module_name, module_hash) for private PDBs — isolated per account, never shared across customers, used to symbolicate your own modules during analysis.

9. Account

PATCH/api/v1/customers/me/retention

Body: {retention_preference_days} — how long uploaded dumps are retained.

10. Webhooks

POST/api/v1/customers/me/webhook

Body: {url, secret}url must be a public http(s) address; secret is 16–256 characters of your choosing. Once registered, your endpoint receives a POST when a dump's report is delivered, instead of (or alongside) polling §7. Failed deliveries are retried.

Every delivery is signed with your secret so you can verify it came from us:

X-Triage-Timestamp: 1789761600
X-Triage-Signature: sha256=<hex HMAC-SHA256(secret, "<timestamp>.<raw request body>")>

Compute the HMAC over the timestamp, a literal ., and the raw body bytes exactly as received (don't re-serialize the JSON), compare in constant time, and reject timestamps more than five minutes old:

import hashlib, hmac, time

def verify(secret: str, headers, raw_body: bytes) -> bool:
    ts = headers["X-Triage-Timestamp"]
    if abs(time.time() - int(ts)) > 300:
        return False
    expected = "sha256=" + hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, headers["X-Triage-Signature"])

11. Errors

StatusMeaning
401Missing, malformed, or invalid API key.
403Valid key, wrong permissions (staff-only routes).
404No such dump/report/customer, or it belongs to a different account.
409Signup email already registered and verified.
422Malformed request body, or an unrecognized dump format.
429Monthly quota exceeded, or a signup/verification resend was attempted too soon.