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 — bashcurl 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.
textstring- Up to 10,000 characters.
surfaceIdsstring[]- Screen ids from GET /surfaces, e.g. "amazon-title".
mustKeepstring[]- Phrases that must stay visible (max 10).
brandstring- For marketplace titles that should start with the brand.
customSurfacesobject[]- Inline limits: { name, limit: { kind: "chars", max } | { kind: "pixels", box }, enforcement, ellipsis }.
smsobject- { pricePerSegment, recipients, maxSegments } for cost estimates.
Request — bashcurl -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.
textstring- The copy to fix.
surfaceIdstring- One screen id (or customSurface inline).
useAiboolean- Allow an AI rewrite if rules are not enough.
allowCutboolean- 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 — bashcurl -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 — bashcurl -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.