API · v1

Check copy before it ships.

Send text, get back exactly what each screen shows, the cut point and any rule problems. Available on every paid plan.

Authentication

Create a key under API keys in the app (any paid plan). Send it as a Bearer token. Keys are shown once and stored hashed — treat them like passwords. Every call returns JSON wrapped in { data } or { error: { code, message } }, and the header X-API-Version: 1.

Header — bash
curl https://truncly.app/api/v1/surfaces \
-H "Authorization: Bearer tr_live_YOUR_KEY"

POST /fit — measure

Measures text on one or more screens. Omit surfaceIds to check all of them. Each result says whether it fits, what is visible, what is hidden, the used and maximum size, detected key info and any rule problems. One API check per request.

text string
Up to 10,000 characters.
surfaceIds string[]
Screen ids from GET /surfaces, e.g. "amazon-title".
mustKeep string[]
Phrases that must stay visible (max 10).
brand string
For marketplace titles that should start with the brand.
customSurfaces object[]
Inline limits: { name, limit: { kind: "chars", max } | { kind: "pixels", box }, enforcement, ellipsis }.
sms object
{ pricePerSegment, recipients, maxSegments } for cost estimates.
Request — bash
curl -X POST https://truncly.app/api/v1/fit \
-H "Authorization: Bearer tr_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Acme Trail Running Shoes for Men, Lightweight Breathable Mesh, Non-Slip Sole, Size 10",
"surfaceIds": ["amazon-title", "google-shopping-visible"],
"brand": "Acme"
}'

POST /fix — fit it

Returns a version that fits one screen: compliance clean-up, plain SMS characters and tighter wording first; optional AI rewrite (one AI credit when it succeeds; misses are free up to your monthly credit count); optional cut at the last whole word.

text string
The copy to fix.
surfaceId string
One screen id (or customSurface inline).
useAi boolean
Allow an AI rewrite if rules are not enough.
allowCut boolean
Cut at a whole word as a last resort.
Response (shortened) — json
{
"data": {
"text": "Acme Trail Running Shoes for Men, Lightweight Breathable Mesh, Size 10",
"status": "fixed",
"changes": [{ "rule": "promo-phrase", "label": "Removed \"best seller\"" }],
"after": { "fits": true, "used": 70, "max": 75 }
}
}

POST /kits — fit everywhere

One message in, a fitted version for up to 12 screens out. Counts one API check per screen.

Request — bash
curl -X POST https://truncly.app/api/v1/kits -H "Authorization: Bearer tr_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"text":"Spring sale: 30% off everything until Sunday","surfaceIds":["apple-mail-iphone-subject","ios-push-title","sms"]}'

POST /languages/check — other languages

mode "estimate" predicts whether the text still fits after translation (free). mode "translate" returns AI translations measured against the limit (one AI credit per language that comes back).

Request — bash
curl -X POST https://truncly.app/api/v1/languages/check -H "Authorization: Bearer tr_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"text":"Acme Trail Running Shoes for Men","surfaceId":"amazon-title","languages":["de","fr"],"mode":"estimate"}'

Errors & limits

Errors use HTTP status codes with a stable code: validation_error (400), unauthorized (401), quota_exceeded or plan_required (402), not_found (404), rate_limited (429), service_unavailable (503). API checks count against your monthly plan quota. Rate limits per IP: /fit 180 a minute, /fix, /kits and /languages/check 60 a minute, everything else 600 a minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 also sends Retry-After. The API is versioned in the path — breaking changes ship as /api/v2.