← Raise Ready Token page

Raise Ready API

Everything the web app does, you can do from your own code: send one canonical set of company facts and get back a drafted fundraising asset together with the fact base it was built from, the cross-checks that were run on the numbers, the gaps you still have to fill and the questions a partner will ask. Useful for regenerating a one-pager whenever your metrics change, drafting application answers for a batch of accelerators, or refusing to publish anything that does not come back “Send-ready”. Base URL https://api.skillsafe.ai/v1/app-api.

Endpoints

There is no /apps/{slug}/ segment in any of these paths — the app slug is bound to your token when you create it at /guest, or by signing in on this origin. Getting that wrong returns 404 not_found.

POST /guest GET /me POST /estimate POST /run GET /jobs/{job_id} POST /run-stream
Every response is wrapped in the same envelope: {"ok":true,"data":{…}} on success, {"ok":false,"error":{"code":"…","message":"…"}} on failure. Check ok before reading data.

Input fields

The object you send to /estimate, /run and /run-stream. Only facts and asset are required.

FieldTypeMeaning
factsstringRequired. The source of truth as written: what the company does, traction with dates, pricing, the raise and its instrument, use of funds, team, milestones. Messy, partial or contradictory notes are expected — conflicts are surfaced rather than papered over. Clipped at 40,000 characters from the middle, keeping both ends, because a founder’s notes open with the company and close with the ask.
assetstringRequired. Exactly one of One-pager, Investor memo, Application answers, Deck outline — spelled and capitalised exactly that way. Anything else is a validation_error.
notesstringOptional. Audience and framing: the stage, the fund or accelerator, tone constraints, what to lead with. For Application answers the questions themselves live here; with none supplied a standard set is answered. Clipped at 6,000 characters.
existingstringOptional. A draft you already have. When present the asset comes back as a revision of it — what holds up is kept, what conflicts with facts is fixed, and every substantive change is accounted for under Assumptions and gaps with a Revised: prefix. Clipped at 20,000 characters.
lintstringOptional. A summary of mechanical checks you ran yourself over the same text. Treated as an untrusted hint: each finding is re-verified against facts before it is repeated, and anything unconfirmable is dropped. The web app supplies its browser-side fact check here.
retry_notestringOptional, and not for humans. Tells the model its previous reply did not parse and to re-emit the same asset in the required shape. Reuse the same Idempotency-Key when you send it.

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 is enough for /me and /estimate; a signed-in token is needed to run unless the app is sponsoring guests.

Or mint a guest token from a script

2. Check who you are and what you can spend

GET /me is free. It tells you whether the token is personal or a guest, and the credit balance a run would draw on.

3. Estimate before you run

POST /estimate is free: it creates no job and charges nothing. It returns the model this app is bound to, the publisher markup, and hold_credits — the amount reserved for a run, which prices the full output cap. The actual charge is usually far lower. Compare hold_credits against the balance from /me and refuse to submit when it is short; a 402 after submit is a failure of your client, not of the user.

This app is pinned to gpt-terra, the balanced OpenAI tier alias, which currently resolves to gpt-5.6-terra at markup_bps: 1000 (a 10% publisher cut). Asserting those three fields off /estimate is the cheapest way to confirm you are talking to the app you think you are.

4. Run it

The request body is the input object directly — there is no {"input": {…}} wrapper. POST /run returns a job_id you poll; GET /jobs/{job_id} reports state and, once terminal, output.output.

Always send an Idempotency-Key. Runs are billed. A retried POST carrying the same key returns the original job instead of starting — and billing — a second one. Derive it from a hash of the input plus an attempt counter, and reuse the same key when you resend with retry_note.

5. Or stream it

POST /run-stream emits server-sent events: a job event, then delta events carrying text as the reply is written, then a done event with the authoritative full output, charged_credits and truncated. Prefer the done payload over your accumulated deltas — a stream can drop its tail. If it dies mid-body, keep what parsed rather than discarding work already paid for.

6. The output contract

The reply is plain text, not JSON. Four tag lines, then six ## sections in exactly this order. A reply that breaks any of these rules should be re-requested with retry_note rather than parsed loosely.

ElementRule
ASSET:First line. Echoes the requested asset exactly: One-pager, Investor memo, Application answers or Deck outline.
VERDICT:Exactly one of Send-ready, Needs your numbers, Not enough to draft. Needs your numbers guarantees at least one bullet under Assumptions and gaps.
CONFIDENCE:A bare integer 0–100. No percent sign, no range, no words.
SUMMARY:2–4 sentences. May wrap over several lines; ends at the first blank line.
## The assetThe drafted material itself, ready to send. Uses ### for internal structure — one per memo section, per application question, or per slide — never ##.
## Source of truthBullets, each <label>: <value>. A number that appears in the asset but not here is a defect.
## Consistency checkBullets. Each cross-check run and what it found, with the arithmetic shown.
## Assumptions and gapsBullets, or the single bullet None. Each missing fact matches a <placeholder> in the asset.
## Red flagsBullets, or the single bullet None.
## Investor questionsBullets. 3–6 questions a partner would ask.

A real reply, abbreviated

ASSET: One-pager
VERDICT: Needs your numbers
CONFIDENCE: 72
SUMMARY: Drafted a seed one-pager for Northwind Freight Accounting around the
strongest fact in the material - MRR growing from $3.1k in January to $8.4k in
May 2026. The raise is stated twice with different amounts, so the ask carries a
placeholder until you confirm which figure is right.

## The asset

### What we do
Northwind Freight Accounting automates settlement for mid-market carriers.

### Traction
$8.4k MRR as of May 2026, up from $3.1k in January - 31 paying carriers at
$270/mo each.

### The ask
Raising <the confirmed raise amount> on a SAFE at a $12M post-money cap.

## Source of truth
- What we do: automated settlement for mid-market carriers
- MRR: $8.4k as of May 2026, up from $3.1k in January
- Customers: 31 paying carriers
- Pricing: $270/mo per carrier
- Raise: stated as both $1.5M and $1.2M
- Instrument: SAFE, $12M post-money cap

## Consistency check
- 31 carriers x $270/mo = $8,370/mo, consistent with the stated $8.4k MRR.
- Use of funds 55% + 25% + 20% = 100%, an allocation that adds up.
- Raise appears with two values, $1.5M and $1.2M - the asset uses a placeholder
  rather than picking one.

## Assumptions and gaps
- The raise amount: the facts state $1.5M in one line and $1.2M in another.
  Confirm which is current.

## Red flags
- MRR of $8.4k is early for a $12M post-money cap; expect the cap to be
  questioned against the traction.

## Investor questions
- Which of $1.5M and $1.2M is the round you are actually raising?
- What is monthly logo churn across the 31 carriers?
- What does the $270/mo price look like at 90 carriers - same price, or tiered?

Parsing it

Two consistency rules are worth enforcing client-side, because the app itself does: a Send-ready verdict whose asset still contains a <placeholder> should be treated as Needs your numbers, and a Needs your numbers verdict with nothing under Assumptions and gaps should not be trusted as complete.

Errors

Failures come back as {"ok":false,"error":{"code":…,"message":…}}.

CodeHTTPWhat to do
unauthorized401The token is missing, malformed, stale or revoked. Mint a new one on the token page.
payment_required402The balance is below min_credits. Preflight with /estimate against /me and this never fires after submit.
not_found404Almost always a wrong path. There is no /apps/{slug}/ segment — the slug is bound to the token at /guest.
validation_error400The input object failed validation — usually asset not being one of the four exact strings, or facts empty.
rate_limited429Too many calls. Back off and retry; do not tight-loop.
sponsor_exhausted402A guest token hit the app’s daily sponsorship budget. Sign in for a personal token.
internal_error500Transient. Retry with the same Idempotency-Key so you are not billed twice.

Keeping your assets in agreement

The rule this app inherits from @affaan-m/investor-materials is that all investor materials must agree with each other — not just that any one of them is internally consistent. The API makes that enforceable: run the same facts through each of the four asset types, then compare the ## Source of truth sections. They are guaranteed to be <label>: <value> bullets, so the same label appearing with two different numbers across two assets is a conflict you can fail a build on. The web app runs exactly this check in the browser across your saved drafts.