← Before the Fill
API

Drive Before the Fill from your own code

The one metered task, check, is available over HTTP. It takes one planned trade - symbol, side, entry, stop, target, multiplier, the account size, the size you meant to place, your win rate, your limits, the positions already open and a line on why you are taking it - and returns a risk read: a verdict (take, resize, wait or skip) that keeps to the page's gate, the size to place, a read of the stop (sound, tight, wide or unclear), what the target and the edge come to, how the book and this trade interact, the events the thesis names, a plan for after the fill, a pre-click checklist and what proves the idea wrong.

The division of labour first: the page counts; the model judges. The page sizes the trade from the stop at your risk per trade, caps it by your position, heat and group limits, works out reward to risk, the break-even win rate, the expectancy at your win rate, the open heat before and after, the losing-streak table and the 1R levels, decides the gate, and sends it all as facts and gate. The model must not recompute them differently. After the reply, the page holds it to the gate and the limits and lists anything that disagrees. Risk arithmetic, not investment advice: the read never says where a price is going.

Base URL and the envelope

Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response uses one envelope:

{ "ok": true,  "data":  { ... } }
{ "ok": false, "error": { "code": "...", "message": "..." } }

The token is minted for this app (the guest call takes {"slug":"before-the-fill"}), so no slug header is needed afterwards. Send it as Authorization: Bearer …. The run body is the input object, sent bare.

StatusCodeMeaning
400validation_errorThe body is not a JSON object, or a required field (task, symbol, side, currency, account, entry, stop, target, multiplier, planned_size, group, atr, win_rate, avg_win_r, limits, open_book, thesis, gate, facts) is missing.
401unauthorizedNo token, or a stale one. Mint a guest token or sign in again.
402insufficient_creditsThe balance is under min_credits. Price with /estimate first.
403forbiddenA guest token tried to run: the risk read is metered and needs a personal sign-in.
404not_foundUnknown job id.
429rate_limitedBack off and retry.
5xxserver_errorTransient. Retry with the same Idempotency-Key so a retry never double-bills.

The task field, the input and the rules

Every run sends task: check (the one task is check); a missing or different one is still answered as check. All fields are strings.

FieldRequiredWhat it holds
taskyesAlways check.
symbolyesThe symbol, as you trade it (up to 16 characters).
sideyeslong or short.
currencyyesUSD, EUR, GBP, CAD or AUD - the account currency.
accountyesThe account size.
entryyesThe entry price.
stopyesThe stop price: below the entry for a long, above it for a short.
targetyesThe target price, or none.
multiplieryesMoney per point per unit: 1 for shares, the contract multiplier for futures.
planned_sizeyesThe size you meant to place, or none.
groupyesYour tag for what the trade moves with, or none.
atryesThe average true range you use, or none.
win_rateyesYour win rate in percent, or none.
avg_win_ryesYour average winner in R, or none.
limitsyesYour limits as one line: risk per trade, open heat, group and position percents and the size step.
open_bookyesThe open positions, one a line (SYMBOL side qty entry stop, optional now, x multiplier, #group), or none.
thesisyesWhy you are taking it and what proves it wrong, or none (up to 1,500 characters).
gateyesThe page's gate: take, resize, wait or skip.
factsyesThe page's sums, one line each: the trade, the risk per unit, the limits, the size by each limit and the maximum, the half size, the risk and reward at the maximum, the planned size, reward to risk, your record and this trade's expectancy, the open book line by line, the group, the losing streaks, the 1R levels and the gate with its reasons. Build it with TradeKit.buildInput.
retry_notenoOnly on a reformat retry: why the previous reply was unusable.

The sums: risk per unit is the entry-to-stop distance plus slippage, times the multiplier. Size by risk is the account times the risk per trade, less the round-trip commission, over the risk per unit, rounded down to the size step. The position limit caps the position's value; the heat limit caps the open risk of the whole book (each held position's risk runs from its current price, or its entry, to its stop); the group limit caps the open risk of one tag. The smallest size wins. Reward to risk is the distance to the target, less slippage, over the risk distance; the break-even win rate and the expectancy assume every trade ends at the target or the stop.

The gate, in order: a negative expectancy at your win rate, or a stop too far for one unit, is skip; no heat or group room is wait; a planned size over the maximum is resize; otherwise take. The reply keeps to it - it may only turn a take into a resize at the half size, and only for a stop under 1 ATR, an event in the holding period the thesis has no plan for, or the thesis saying the book already holds the same idea. The size is the planned size or the maximum for take, the maximum for resize and 0 for wait and skip.

The reply

One JSON object, no prose around it:

{"task": "check", "headline": "...", "verdict": "take", "size": 75, "size_why": "...", "stop": {"read": "sound", "note": "..."}, "target": {"note": "..."}, "edge": "...", "book": "...", "events": ["..."], "plan": [{"when": "...", "do": "..."}], "before_you_click": ["...", "...", "..."], "wrong_if": "..."}
FieldWhat it holds
headlineOne sentence: the verdict, the size and the one thing that decided it.
verdicttake, resize, wait or skip.
sizeA number of units to place (0 for wait and skip).
size_whyOne or two sentences naming the limit that set the size.
stopread (sound, tight, wide or unclear) and a note.
targetA note on the target and reward to risk, or that there is none.
edgeReward to risk, the break-even win rate and the expectancy at your win rate, in words.
bookOpen heat before and after, the room left, the group, and anything that looks like the same bet.
events[]Up to three forward-looking risks the thesis names; empty if none.
plan[]Two to four {when, do} steps for after the fill, or what would have to change for a wait or skip.
before_you_click[]Three to five checks to make before placing the order.
wrong_ifWhat proves the idea wrong, from the thesis.

The page reads the reply with ReplyKit.normalize and checks it with ReplyKit.check, which lists, under "The page's check", a verdict that leaves the gate, a size over the maximum, a non-zero size on a wait or skip, a size off your size step, a stop read that disagrees with the ATR multiple, a plan step that widens a stop or adds to a loser, events when no thesis was given, and an R multiple quoted when there is no target.

Worked examples - every gate

These are the free samples on the page: the exact input the page sends and the reply that replays for free. The prices are made up for the samples. Together they cover every gate: take, resize, wait and skip.

A breakout, inside the limits - take it, size 75

Input:

{
 "task": "check",
 "symbol": "AMD",
 "side": "long",
 "currency": "USD",
 "account": "60000",
 "entry": "152.40",
 "stop": "144.90",
 "target": "172.00",
 "multiplier": "1",
 "planned_size": "75",
 "group": "semis",
 "atr": "4.10",
 "win_rate": "45",
 "avg_win_r": "2.1",
 "limits": "risk 1%, heat 6%, group 3%, position 25%, step 1",
 "open_book": "NVDA long 40 118.5 112 now 124 #semis\nXLE long 120 88.2 85.1\nJPM long 30 241 233.5 #banks",
 "thesis": "Daily breakout above a seven-week base at 150 on volume 1.8x the 50-day average. Stop under the base low and the 20-day line. Earnings are in 11 trading days; I want to be at breakeven or out before then. Wrong if it closes back inside the base.",
 "gate": "take",
 "facts": "Trade: long AMD, entry 152.40, stop 144.90 (7.50 away, 4.92%, 1.83 ATR), target 172.00.\nRisk per unit: $7.55 (includes 0.05 slippage).\nLimits: risk per trade 1.00% of $60,000.00 = $600.00; open heat limit 6.00% = $3,600.00; group limit 3.00%; position limit 25% of the account; size step 1.\nSizes: by risk 79, by position limit 98, by heat room 334, by #semis group room 174. Maximum size: 79 (set by your risk per trade).\nHalf size (for a resize under rule 3): 39, risk $294.45 = 0.49%; open heat after it $1,371.45 = 2.29%; #semis after it $774.45; reward at target $764.40.\nAt the maximum size: risk $596.45 = 0.99% of the account, position value $12,039.60 = 20.1%, reward at target $1,548.40.\nPlanned size: 75, which risks $566.25 = 0.94% of the account - inside the maximum; at the planned size open heat after this trade would be $1,643.25 = 2.74%, leaving $1,956.75, and the reward at target $1,470.00.\nReward to risk: 2.59R after slippage; break-even win rate 27.9% (fees included).\nYour record: win rate 45%, average winner 2.10R (record expectancy 0.40R a trade); this trade's expectancy at your win rate 0.62R.\nOpen book (3 positions): open risk $1,077.00 = 1.80%; heat room $2,523.00; after this trade at the maximum size $1,673.45 = 2.79%, leaving $1,926.55 of room.\n  - NVDA long 40 from 118.5, stop 112, now 124, #semis: open risk $480.00 (from now 124 to the stop).\n  - XLE long 120 from 88.2, stop 85.1: open risk $372.00 (from entry 88.2 to the stop).\n  - JPM long 30 from 241, stop 233.5, #banks: open risk $225.00 (from entry 241 to the stop).\nGroup #semis: open $480.00, after this trade $1,076.45, limit $1,800.00.\nLosing streaks at 1.00% a trade: 3 in a row -3.0%, 5 in a row -4.9%, 8 in a row -7.7%, 10 in a row -9.6%; at your win rate expect a run of about 8 losses somewhere in 100 trades.\n1R levels: +1R 159.90, +2R 167.40, +3R 174.90.\nGate: take - inside every limit."
}

Reply:

{
 "task": "check",
 "headline": "Take 75 shares, since size, stop, and heat all sit inside the limits and the earnings in 11 days is already covered by your own exit plan.",
 "verdict": "take",
 "size": 75,
 "size_why": "Your planned 75 shares stays inside the 79-share maximum set by your risk per trade (1% = $600.00), so the planned size stands without adjustment.",
 "stop": {
  "read": "sound",
  "note": "The stop at 144.90 sits under the base low and the 20-day line - past 150, the breakout level where the thesis says a close back inside the base proves it wrong - and at 1.83 ATR it's also inside the normal band."
 },
 "target": {
  "note": "Target 172.00 gives 2.59R reward to risk after slippage, between +2R (167.40) and +3R (174.90)."
 },
 "edge": "At 2.59R reward to risk you only need a 27.9% win rate to break even; your actual record is 45% with a 2.10R average winner (0.40R record expectancy), putting this trade's expectancy at 0.62R.",
 "book": "Open risk is $1,077.00 (1.80%) before this trade; at your planned 75 shares it rises to $1,643.25 (2.74%), leaving $1,956.75 of the $3,600.00 heat limit. The #semis group sits at $480.00 now; facts put it at $1,076.45 even at the full 79-share maximum, well under the $1,800.00 group limit, so 75 shares leaves more room still. NVDA carries the same #semis tag as this trade - worth checking it isn't the same semiconductor move doubled up; XLE and JPM share no tag or thesis link with this one.",
 "events": [
  "Earnings in 11 trading days - the point by which the thesis plans to be flat or at breakeven"
 ],
 "plan": [
  {
   "when": "price reaches +1R (159.90)",
   "do": "move the stop to entry (152.40)"
  },
  {
   "when": "price reaches +2R (167.40)",
   "do": "trail the stop up to +1R (159.90)"
  },
  {
   "when": "11 trading days pass and earnings approach",
   "do": "be at breakeven or flat, as the thesis plans, regardless of where price sits"
  },
  {
   "when": "price reaches the target (172.00)",
   "do": "take profit on the position"
  }
 ],
 "before_you_click": [
  "Confirm the entry is still near 152.40 - the size and risk math assume this price",
  "Place the stop at 144.90, under both the base low and the 20-day line",
  "Confirm the earnings date is 11 trading days out and set a reminder to be flat or breakeven by then",
  "Check NVDA's #semis exposure against this one before adding it",
  "Confirm your broker shows open risk at $1,077.00 and #semis at $480.00 before this trade"
 ],
 "wrong_if": "Closes back inside the base, per the thesis."
}

Too many shares - resize it, size 378

Input:

{
 "task": "check",
 "symbol": "SOFI",
 "side": "long",
 "currency": "USD",
 "account": "25000",
 "entry": "14.20",
 "stop": "13.55",
 "target": "16.10",
 "multiplier": "1",
 "planned_size": "1000",
 "group": "none",
 "atr": "0.48",
 "win_rate": "50",
 "avg_win_r": "1.6",
 "limits": "risk 1%, heat 6%, group 3%, position 25%, step 1",
 "open_book": "KO long 50 70.1 67.8",
 "thesis": "Gap-fill setup after a dip to the 50-day. I am very confident on this one so I want a full-size position, 1,000 shares. Wrong if it loses 13.55.",
 "gate": "resize",
 "facts": "Trade: long SOFI, entry 14.20, stop 13.55 (0.65 away, 4.58%, 1.35 ATR), target 16.10.\nRisk per unit: $0.66 (includes 0.01 slippage).\nLimits: risk per trade 1.00% of $25,000.00 = $250.00; open heat limit 6.00% = $1,500.00; group limit 3.00%; position limit 25% of the account; size step 1.\nSizes: by risk 378, by position limit 440, by heat room 2,098. Maximum size: 378 (set by your risk per trade).\nHalf size (for a resize under rule 3): 189, risk $124.74 = 0.50%; open heat after it $239.74 = 0.96%; reward at target $359.10.\nAt the maximum size: risk $249.48 = 1.00% of the account, position value $5,367.60 = 21.5%, reward at target $718.20.\nPlanned size: 1,000, which risks $660.00 = 2.64% of the account - over the maximum.\nReward to risk: 2.86R after slippage; break-even win rate 25.9% (fees included).\nYour record: win rate 50%, average winner 1.60R (record expectancy 0.30R a trade); this trade's expectancy at your win rate 0.93R.\nOpen book (1 position): open risk $115.00 = 0.46%; heat room $1,385.00; after this trade at the maximum size $364.48 = 1.46%, leaving $1,135.52 of room.\n  - KO long 50 from 70.1, stop 67.8: open risk $115.00 (from entry 70.1 to the stop).\nGroup: none tagged for this trade.\nLosing streaks at 1.00% a trade: 3 in a row -3.0%, 5 in a row -4.9%, 8 in a row -7.7%, 10 in a row -9.6%; at your win rate expect a run of about 7 losses somewhere in 100 trades.\n1R levels: +1R 14.85, +2R 15.50, +3R 16.15.\nGate: resize - the planned 1,000 is more than the 378 the limits allow (it risks $660.00, 2.64%)."
}

Reply:

{
 "task": "check",
 "headline": "Resize to 378 shares - the 1,000 you planned risks 2.64%, well over the 1% per-trade limit.",
 "verdict": "resize",
 "size": 378,
 "size_why": "The $250.00 risk-per-trade limit (1.00% of $25,000.00) caps size at 378 units, risking $249.48 (1.00%); the 1,000 shares you planned would have risked $660.00 (2.64%), over the limit. Feeling very confident on a setup is exactly when a limit like this earns its keep.",
 "stop": {
  "read": "sound",
  "note": "The thesis says 'Wrong if it loses 13.55' - the same price as the stop, and facts put it at 1.35 ATR, not tight itself. The stop sits right at the level that proves the idea wrong, so it reads sound."
 },
 "target": {
  "note": "Target 16.10 gives 2.86R reward-to-risk after slippage, worth $718.20 against $249.48 at risk at the 378-share size."
 },
 "edge": "Reward to risk is 2.86R after slippage, above the 25.9% break-even win rate; at your 50% win rate this trade's expectancy is 0.93R, above your overall record expectancy of 0.30R a trade.",
 "book": "Open heat is $115.00 (0.46%) before this trade, with $1,385.00 of room under the $1,500.00 limit; at 378 shares heat rises to $364.48 (1.46%), leaving $1,135.52 of room. No group tag here, and KO doesn't look like the same bet as this trade.",
 "events": [],
 "plan": [
  {
   "when": "price reaches +1R (14.85)",
   "do": "move the stop to breakeven (14.20)"
  },
  {
   "when": "price reaches +2R (15.50)",
   "do": "trail the stop up to +1R (14.85)"
  },
  {
   "when": "price reaches the target (16.10)",
   "do": "close the position and take the 2.86R gain"
  }
 ],
 "before_you_click": [
  "Confirm the order is sized at 378 shares, not the 1,000 originally planned.",
  "Place the stop at 13.55 (1.35 ATR, 0.65 below entry) with the entry.",
  "Check SOFI is still trading near 14.20 so the risk per share hasn't drifted from $0.66.",
  "Confirm the open KO position ($115.00 risk) hasn't changed since these numbers were computed.",
  "Re-check the gap-fill setup off the 50-day is still intact before clicking."
 ],
 "wrong_if": "Wrong if SOFI loses 13.55 - the level the thesis names and where the stop sits."
}

Futures into a full book - wait, size 0

Input:

{
 "task": "check",
 "symbol": "MES",
 "side": "long",
 "currency": "USD",
 "account": "40000",
 "entry": "5812.25",
 "stop": "5790.00",
 "target": "5860.00",
 "multiplier": "5",
 "planned_size": "2",
 "group": "index",
 "atr": "18.5",
 "win_rate": "48",
 "avg_win_r": "1.9",
 "limits": "risk 1%, heat 6%, group 3%, position 100%, step 1",
 "open_book": "MNQ long 2 20410 20300 x2 #index\nAAPL long 100 228.5 221 #tech\nMSFT long 40 431 418 now 436 #tech\nGLD long 30 241 232\nMCL short 2 71.4 73.2 x100",
 "thesis": "Opening-range breakout on the micro S&P after a higher low at 5790. Target is the prior day high. Wrong below 5790.",
 "gate": "wait",
 "facts": "Trade: long MES (multiplier 5), entry 5812.25, stop 5790.00 (22.25 away, 0.38%, 1.20 ATR), target 5860.00.\nRisk per unit: $112.50 (includes 0.25 slippage); round-trip commission $2.50.\nLimits: risk per trade 1.00% of $40,000.00 = $400.00; open heat limit 6.00% = $2,400.00; group limit 3.00%; position limit 100% of the account; size step 1.\nSizes: by risk 3, by position limit 1, by heat room 0, by #index group room 6. Maximum size: 0 (set by the heat left in the book).\nAt the maximum size: risk $0.00 = 0.00% of the account, position value $0.00 = 0.0%, reward at target $0.00.\nPlanned size: 2, which risks $227.50 = 0.57% of the account - over the maximum.\nReward to risk: 2.11R after slippage; break-even win rate 32.1% (fees included).\nYour record: win rate 48%, average winner 1.90R (record expectancy 0.39R a trade); this trade's expectancy at your win rate 0.49R.\nOpen book (5 positions): open risk $2,540.00 = 6.35%; heat room $0.00 (the book is already $140.00 over its heat limit); after this trade at the maximum size $2,540.00 = 6.35%, leaving $0.00 of room.\n  - MNQ long 2 x2 from 20410, stop 20300, #index: open risk $440.00 (from entry 20410 to the stop).\n  - AAPL long 100 from 228.5, stop 221, #tech: open risk $750.00 (from entry 228.5 to the stop).\n  - MSFT long 40 from 431, stop 418, now 436, #tech: open risk $720.00 (from now 436 to the stop).\n  - GLD long 30 from 241, stop 232: open risk $270.00 (from entry 241 to the stop).\n  - MCL short 2 x100 from 71.4, stop 73.2: open risk $360.00 (from entry 71.4 to the stop).\nGroup #index: open $440.00, after this trade $440.00, limit $1,200.00.\nLosing streaks at 1.00% a trade: 3 in a row -3.0%, 5 in a row -4.9%, 8 in a row -7.7%, 10 in a row -9.6%; at your win rate expect a run of about 7 losses somewhere in 100 trades.\n1R levels: +1R 5834.50, +2R 5856.75, +3R 5879.00.\nGate: wait - open risk $2,540.00 (6.35%) leaves no room under the 6.0% heat limit ($2,400.00); the planned 2 is more than the 0 the limits allow (it risks $227.50, 0.57%)."
}

Reply:

{
 "task": "check",
 "headline": "Wait, size 0 - the open book is already $140.00 over its 6.00% heat limit, leaving no room for this MES trade.",
 "verdict": "wait",
 "size": 0,
 "size_why": "Maximum size is 0, set by the heat left in the book: open risk is already $2,540.00 (6.35%), $140.00 over the $2,400.00 (6.00%) heat limit, so there is $0.00 of room no matter what the $400.00 per-trade cap or the #index group's $1,200.00 limit would otherwise allow.",
 "stop": {
  "read": "sound",
  "note": "The stop at 5790.00 is 1.20 ATR away and sits exactly at the level the thesis calls wrong-if ('higher low at 5790 ... Wrong below 5790'), so it's placed where the idea itself is disproven."
 },
 "target": {
  "note": "Target 5860.00 is the prior day high per the thesis, giving 2.11R reward to risk after slippage."
 },
 "edge": "Reward to risk is 2.11R after slippage, with a 32.1% break-even win rate; at your 48% record this trade's expectancy works out to 0.49R, above your 0.39R average per-trade expectancy.",
 "book": "The book is already $140.00 over its heat limit - open risk is $2,540.00 (6.35%) against the $2,400.00 (6.00%) cap - so no new risk can go on until it's back under that; at the maximum size of 0, this trade leaves it exactly where it is, $2,540.00 (6.35%) with $0.00 of room. The #index group sits at $440.00 of its $1,200.00 limit, all from the open MNQ long tagged #index - the same bet tag as this trade. No other open position shares a tag or a stated link to this one.",
 "events": [],
 "plan": [
  {
   "when": "open book heat drops back under the $2,400.00 (6.00%) limit (something in the book closes or is trimmed)",
   "do": "that is the only thing that frees up size for this trade - re-run the check once it does"
  },
  {
   "when": "the check is re-run",
   "do": "treat it as a fresh read - do not reuse today's $0 maximum or the planned size of 2 without new numbers"
  }
 ],
 "before_you_click": [
  "Confirm total open heat is back under the $2,400.00 (6.00%) limit before treating this as live again.",
  "Re-run the check for a fresh maximum size and risk numbers rather than reusing today's.",
  "Check the #index group still has room under its $1,200.00 limit for whatever size comes back.",
  "Make sure the 5790 higher-low setup and the prior-day-high target are still in place.",
  "Keep the stop at 5790.00, the thesis's wrong-if level - do not widen it to fit a size."
 ],
 "wrong_if": "Wrong below 5790.00, per the thesis."
}

A short that does not pay - skip it, size 0

Input:

{
 "task": "check",
 "symbol": "SAP",
 "side": "short",
 "currency": "EUR",
 "account": "30000",
 "entry": "236.50",
 "stop": "243.00",
 "target": "231.00",
 "multiplier": "1",
 "planned_size": "40",
 "group": "none",
 "atr": "5.20",
 "win_rate": "40",
 "avg_win_r": "1.5",
 "limits": "risk 1%, heat 6%, group 3%, position 25%, step 1",
 "open_book": "ASML long 6 652 628\nSIE long 20 214.5 207",
 "thesis": "Fading the rally into the gap from last month. Resistance around 238. Target is the 20-day line at 231. Wrong above 243.",
 "gate": "skip",
 "facts": "Trade: short SAP, entry 236.50, stop 243.00 (6.50 away, 2.75%, 1.25 ATR), target 231.00.\nRisk per unit: €6.60 (includes 0.10 slippage); round-trip commission €9.80.\nLimits: risk per trade 1.00% of €30,000.00 = €300.00; open heat limit 6.00% = €1,800.00; group limit 3.00%; position limit 25% of the account; size step 1.\nSizes: by risk 43, by position limit 31, by heat room 226. Maximum size: 31 (set by the position-size limit).\nHalf size (for a resize under rule 3): 15, risk €108.80 = 0.36%; open heat after it €402.80 = 1.34%; reward at target €72.70.\nAt the maximum size: risk €214.40 = 0.71% of the account, position value €7,331.50 = 24.4%, reward at target €160.70.\nPlanned size: 40, which risks €273.80 = 0.91% of the account - over the maximum.\nReward to risk: 0.82R after slippage; break-even win rate 57.6% (fees included).\nYour record: win rate 40%, average winner 1.50R (record expectancy 0.00R a trade); this trade's expectancy at your win rate -0.32R.\nOpen book (2 positions): open risk €294.00 = 0.98%; heat room €1,506.00; after this trade at the maximum size €508.40 = 1.69%, leaving €1,291.60 of room.\n  - ASML long 6 from 652, stop 628: open risk €144.00 (from entry 652 to the stop).\n  - SIE long 20 from 214.5, stop 207: open risk €150.00 (from entry 214.5 to the stop).\nGroup: none tagged for this trade.\nLosing streaks at 1.00% a trade: 3 in a row -3.0%, 5 in a row -4.9%, 8 in a row -7.7%, 10 in a row -9.6%; at your win rate expect a run of about 9 losses somewhere in 100 trades.\n1R levels: +1R 230.00, +2R 223.50, +3R 217.00.\nGate: skip - at a 40% win rate a 0.82R winner loses 0.32R a trade on average; the planned 40 is more than the 31 the limits allow (it risks €273.80, 0.91%)."
}

Reply:

{
 "task": "check",
 "headline": "Skip, size 0 - at your 40% win rate this 0.82R short averages -0.32R a trade, a losing edge no size fixes (the planned 40 also topped the 31-unit position-size limit).",
 "verdict": "skip",
 "size": 0,
 "size_why": "Size is 0: at a 40% win rate this 0.82R trade averages -0.32R, a losing edge that no size corrects - the planned 40 was also above the 31-unit maximum set by the position-size limit, but that's beside the point now.",
 "stop": {
  "read": "sound",
  "note": "The thesis says the idea is wrong above 243.00, and the stop sits right there, 1.25 ATR away - too far from 1 ATR to be tight, nowhere near 3 to be wide."
 },
 "target": {
  "note": "The target is 231.00, the thesis's 20-day line, giving 0.82R reward to risk after slippage."
 },
 "edge": "Reward to risk is 0.82R after slippage against a 57.6% breakeven win rate; at your actual 40% win rate (1.50R average winner) this trade's expectancy is -0.32R.",
 "book": "Since this trade isn't taken, open heat stays at €294.00 = 0.98%, with €1,506.00 of room untouched. No group is tagged. ASML (long 6 from 652) and SIE (long 20 from 214.5) are both long and unrelated to this short SAP idea - nothing here looks like the same bet.",
 "events": [],
 "plan": [
  {
   "when": "Your record win rate on this kind of short fade climbs toward the 57.6% breakeven (it's 40% now)",
   "do": "Re-run the page then - the edge has to turn positive, not just the size."
  },
  {
   "when": "Your average winner on this setup grows well past 1.50R, enough to clear breakeven at a 40% win rate",
   "do": "Re-run the page before sizing it - a bigger average win is what would fix the expectancy, not a smaller position."
  }
 ],
 "before_you_click": [
  "Re-run the page with your current record rather than assuming the edge has changed.",
  "Confirm the thesis still treats 243.00 as the level that proves it wrong before using that stop again.",
  "Check what the position-size limit then allows before sizing - it capped this one at 31 against a planned 40.",
  "Confirm ASML and SIE are still open at the stops shown before adding new risk."
 ],
 "wrong_if": "The thesis says the idea is wrong if price trades above 243.00, the same level as the stop."
}

Build the input yourself

Load the engine in node (global.window = global; require("./tradekit.js"); require("./replykit.js")), then:

const K = TradeKit, R = ReplyKit;
const built = K.buildInput(K.form({ symbol: "AMD", side: "long", entry: "152.40", stop: "144.90", target: "172.00",
  equity: "60000", currency: "USD", planned: "75", win: "45", avgwin: "2.1", group: "semis", atr: "4.10",
  book: "NVDA long 40 118.50 112.00 now 124.00 #semis\nXLE long 120 88.20 85.10",
  thesis: "Breakout above a seven-week base. Wrong if it closes back inside the base." }));  // built.ok is false, with built.note, when the stop is missing or on the wrong side
const wire = K.toWire(built.input);   // POST this to /estimate and /run; built.facts holds every sum, built.facts.gate the gate
// then: const reply = R.normalize(R.parseReply(job.output.output));
// R.check(reply, built).notes        // the page's re-check of the reply
// R.md(built, reply, K.title(built.form))   // the sizing, the book and the read as Markdown

Form keys: symbol, side, entry, stop, target, mult, planned, group, atr, slip, comm, equity, currency, win, avgwin, book, thesis and limits (risk, heat, group, position, step).

Step 1 — a tiny client helper

One function that sends JSON and unwraps the envelope. Paste a personal token from /tokens.html, or leave it empty and mint a guest token in step 2.

BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="paste-your-token-here"   # from https://before-the-fill.skillsafe.ai/tokens.html
api() { # api METHOD PATH [JSON-BODY]
  curl -s -X "$1" "$BASE$2" -H "Content-Type: application/json" \
    ${TOKEN:+-H "Authorization: Bearer $TOKEN"} ${3:+--data "$3"}
}

Step 2 — a token

A guest token is enough for /me and /estimate. A run is metered, so it needs a personal token: sign in on /tokens.html and copy it from there.

# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN=$(curl -s -X POST "$BASE/guest" -H "Content-Type: application/json" -d '{"slug":"before-the-fill"}' | jq -r '.data.token')

Step 3 — GET /me

Who the token is (subject_type: user or guest) and the credit balance.

api GET /me | jq '.data | {subject_type, credits}' 

Step 4 — POST /estimate

Free. The body is the run input itself, the bare object (never wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model_alias reads gpt-terra.

# input.json: the run input object - {"task": "check", "symbol": "AMD", "side": "long", "account": "60000", "entry": "152.40", "stop": "144.90", "...": "...", "gate": "take", "facts": "...", ...}
# - see the field table
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}' 

Step 5 — POST /run, then poll the job

Send an Idempotency-Key built from the lane and the input: a retry with the same key never bills twice. The page uses before-the-fill:<task>:<inputHash>:a<attempt> (the one task is check), and its one reformat retry (with retry_note added) is attempt 2, a new key and a second run. The job's output.output is the reply text; truncated: true means the balance cut it short.

KEY="before-the-fill:check:$(shasum -a 256 input.json | cut -c1-16):a1"
JOB=$(curl -s -X POST "$BASE/run" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $KEY" --data @input.json | jq -r '.data.job_id')
while :; do
  J=$(api GET "/jobs/$JOB"); S=$(echo "$J" | jq -r '.data.status')
  case "$S" in succeeded|failed|cancelled) break;; esac; sleep 2
done
echo "$J" | jq -r '.data.output.output' > reply.json   # one JSON object, the reply contract
echo "$J" | jq '.data | {charged_credits, truncated}' 

Step 6 — POST /run-stream

The same run as Server-Sent Events, with the same input.json. Browsers receive progress ticks rather than text deltas; the final done event carries the reply.

# Server-Sent Events: tick/delta events while the job runs, then a final event with the job
curl -N -s -X POST "$BASE/run-stream" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: before-the-fill:check:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json