Create a prop firm challenge template
A template is what a trader actually buys: an account size, an entry fee, a
payout split, and the rule set the engine judges the run against. When this is
done you have an active template that can be sold as a
paper prop account immediately.
-
Collect the firm and trading group ids
Section titled “Collect the firm and trading group ids”A template belongs to one firm (
firmId) and allocates to one trading group (tradingGroupId).tradingGroupIdis required on create.firmIdis optional: omit it and the template lands on your tenant’s single live firm. That is also the surest way not to send your tenant id where the firm id goes, which is the most common cause of403 forbiddenhere. Omitting is refused — never guessed — when your tenant owns no live firm (403 forbidden) or more than one (400 firm_ambiguous, whosedetaillists them). On update an absentfirmIdmeans “leave the firm alone” and never derives, so aPATCHthat never mentions a firm cannot move the template to another one.The examples below send it explicitly, which is always valid.
Terminal window curl -s https://api.troncharts.xyz/api/v1/trading-groups \-H "authorization: Bearer $TOKEN" \-H "x-tenant-slug: $TC_TENANT_SLUG"# → { "groups": [ { "id": "…", "slug": "crypto-perps", "isDefault": true, … } ] }const { groups } = await sdk.tradingGroups.list()const { firms } = await sdk.firms.list() // needs firm:operate -
Write the rule set
Section titled “Write the rule set”rulesis a discriminated union keyed ontype, one to 32 entries of{ type, value }. An unknowntypefails the body parse with a 400invalid_body, so pick from the catalog rather than inventing a field.[{ "type": "max_drawdown_usd", "value": 1250 },{ "type": "profit_target_usd", "value": 2000 },{ "type": "min_trading_days", "value": 3 }]_usdrules take a plain number in the template’s currency. Every_pctrule takes a 0..1 fraction —max_concentration_pct: 0.3is 30%.The template is the only place you write these. The server materializes a managed risk profile holding them and binds it, so you never create or name a profile for a single program — see How an account is configured.
-
Create the template
Section titled “Create the template”idis yours to choose and must be lower-kebab-case.accountSizeUsd,feeUsdandpayoutSplitPctare decimal strings, not numbers.Terminal window curl -s https://api.troncharts.xyz/api/v1/prop-templates \-H "authorization: Bearer $TOKEN" \-H "x-tenant-slug: $TC_TENANT_SLUG" \-H 'content-type: application/json' \-d '{"id": "acme-25k-two-step","name": "Acme 25K Evaluation","accountSizeUsd": "25000.00","feeUsd": "199.00","payoutSplitPct": "80","durationDays": 30,"firmId": "'"$FIRM_ID"'","tradingGroupId": "'"$GROUP_ID"'","rules": [{ "type": "max_drawdown_usd", "value": 1250 },{ "type": "profit_target_usd", "value": 2000 }]}'# → 201 { "template": { "id": "acme-25k-two-step", "active": true, … } }const { template } = await sdk.propTemplates.create({id: 'acme-25k-two-step',name: 'Acme 25K Evaluation',accountSizeUsd: '25000.00',feeUsd: '199.00',payoutSplitPct: '80',firmId: firmId,tradingGroupId: groupId,rules: [{ type: 'max_drawdown_usd', value: 1250 },{ type: 'profit_target_usd', value: 2000 },],}) -
Confirm it is sellable
Section titled “Confirm it is sellable”The response carries
active: true. Re-read the catalogue to see it beside the rest, then handidandpropTenantIdtocreate-prop.Terminal window curl -s "https://api.troncharts.xyz/api/v1/prop-templates?activeOnly=true" \-H "authorization: Bearer $TOKEN" \-H "x-tenant-slug: $TC_TENANT_SLUG"const { templates } = await sdk.propTemplates.list({ activeOnly: true })
Sharing one rule set across templates
Section titled “Sharing one rule set across templates”Instead of rules, send riskProfileId to point several templates at one
authored profile — useful when three account sizes share the same limits. The
profile’s rules are copied down into the template, so the snapshot each account
freezes still matches exactly.
const { profile } = await sdk.riskProfiles.create({ name: 'Acme 1-step', kind: 'challenge', rules: [{ type: 'max_drawdown_usd', value: 1250 }],})await sdk.propTemplates.create({ /* … */ riskProfileId: profile.id })Other optional fields worth knowing: programKind (challenge or flash), and
either nextStepTemplateId or tierLadder — never both.
Next: Sell a paper prop account · Create a trading group · Prop account model