← Issue Forge Token page

Issue Forge API

Everything the web app does, you can do from your own code: send a rough report, get back a structured issue with a title, a type, labels, a readback, open questions and a confidence line. Useful for wiring triage into a support inbox, a Slack workflow or a bot that files issues from customer reports. Base URL https://api.skillsafe.ai/v1/app-api.

Input fields

The object you send as input. Only report is required.

FieldTypeMeaning
reportstringThe rough report, as written. Rambling, contradictory and partly irrelevant is expected. Clipped at 40,000 characters — from the middle, keeping both ends, with the cut announced in-band as [report truncated: N characters removed from the middle].
contextstringOptional project context: repository or product name, versions, environment, links, related threads. Anything omitted here is never invented — it comes back as an open question.
type_hintstringOptional, one of Bug, Feature, Task, Docs, or empty. Treated as a hint: a report that plainly describes something else is filed under the correct type, with the override explained in the readback.
correctionstringOptional. What the previous readback got wrong, in the reporter's own words. Sent with the original report to produce a corrected issue.

1. Get a token

Every call carries Authorization: Bearer <token>. Open the token page to sign in, reveal your token and copy a ready-made shell export. It never asks you to open the DevTools console. A guest token works for reading and estimating; a signed-in token is needed to run.

2. Check the session and balance

Confirms who the token belongs to and how many credits are available. Do this before a run: a 402 after submitting is avoidable.

GET/me

3. Estimate - free, no job created

Returns the credit hold a run would reserve, plus the resolved model and markup. It creates no job and charges nothing, so it is safe to call on every keystroke.

POST/estimate

4. Run and poll

Creates a job and returns when it is terminal. Always send an Idempotency-Key: a retried request with the same key returns the original job instead of billing twice.

POST/run

5. Run with streaming (SSE)

Same job, delivered as server-sent events. delta events carry incremental text, job carries the job id, and done carries the authoritative full output - trust done over the concatenated deltas, which can drop the tail.

POST/run-stream

Output contract

data.output.output is plain text in exactly this shape. This is what the app's own parser decodes, and the same contract your code should parse against.

TITLE: <sentence-case title, no type prefix>
TYPE: <Bug|Feature|Task|Docs>
LABELS: <comma-separated lowercase labels, or "none">

BODY:
<the issue body in markdown>
Parsing rules, as implemented. A single markdown fence wrapped around the whole reply is stripped first. TITLE: is the first line that starts with it; TYPE: is the first such line after it and must be exactly one of the four words or the parse fails; LABELS: splits on commas and lowercases, with the literal none and a missing line both meaning no labels; the body is everything after a line reading exactly BODY:.

Inside the body

Sections are ### headings matched to the type — What's wrong, Steps to reproduce, Expected vs actual, Environment for a Bug; Problem, Proposed solution, Alternatives considered, Use cases for a Feature. Then, for every type, in order: an unheaded paragraph beginning **Readback:**, a ### Open questions numbered list where blocking items are prefixed Critical:, and a final line Confidence: NN%, <clause>.

Grounding. Reproduction steps, versions, environments, error messages and motivations that are not in report or context will not appear in the output. If you need them, supply them — do not expect the model to guess. That is the point of the tool.

The envelope and error codes

Every response is {"ok": true, "data": {...}} or {"ok": false, "error": {"code": "...", "message": "..."}}. Check ok before reading data.

StatusCodeWhat to do
400VALIDATION_ERRORThe input shape is wrong. error.details names the field.
401UNAUTHORIZEDMissing, malformed or expired token. Mint a new one from the token page.
402PAYMENT_REQUIREDThe balance is below the run's hold. Call /estimate first and compare against /me.
404NOT_FOUNDWrong slug or job id.
429RATE_LIMITEDBack off and retry with the same idempotency key.
5xxINTERNALRetry with the same idempotency key; a completed job is returned rather than re-billed.
Idempotency. Send Idempotency-Key on every /run and /run-stream. Derive it from a hash of the input plus an attempt counter, so a network retry collapses server-side while a genuine re-run gets its own key. The app does exactly this, including on its automatic reformat retry.