← FORMA

FORMA API

Send one camera frame, get body measurements back. Circumferences, landmarks and a parametric mesh, from FORMA's own measurement engine — no third-party model in the path.

No image is ever stored. Pixels are measured in the request and discarded; only the derived numbers are kept.

Try it without paying

Keys beginning forma_test_ run the identical engine and are never counted against an allowance. Build the whole integration on a test key, then swap it for forma_live_ when you go live. Nothing else changes.

Create one at API keys. It is shown once and hashed at rest, so it cannot be shown again — lose it and revoke it rather than hunting for it.

Measure a frame

Two formats. Prefer the binary one: a 1280×1280 frame is 6.5 MB of pixels, and base64 inside JSON makes it 8.7 MB plus a parse and a decode before any measuring starts.

# Raw RGBA in the body — no base64, no JSON parse
curl -X POST https://myforma3d.com/api/v1/scans \
  -H "authorization: Bearer forma_test_YOUR_KEY" \
  -H "content-type: application/octet-stream" \
  -H "x-forma-profile-id: PROFILE_ID" \
  -H "x-forma-width: 720" \
  -H "x-forma-height: 1280" \
  --data-binary @frame.rgba

Or JSON, if that is easier to produce:

curl -X POST https://myforma3d.com/api/v1/scans \
  -H "authorization: Bearer forma_test_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{"profileId":"PROFILE_ID","width":720,"height":1280,"rgbaBase64":"..."}'

The response:

{
  "ok": true,
  "requestId": "req_9f2c…",
  "data": {
    "scanId": "…",
    "environment": "test",
    "billable": false,
    "measurements": {
      "height_cm": 178.0, "chest_cm": 98.4, "waist_cm": 84.1,
      "hips_cm": 99.2, "shoulders_cm": 45.6, "left_thigh_cm": 56.3
    },
    "scores": { "quality": 0.83, "confidence": 0.79, "lighting": 0.71 }
  }
}

Capture quality

A frame that cannot be measured is refused rather than guessed at. Quality below 0.15 returns 422 scan_quality_too_low with the individual scores so you can tell the user what to fix. Weak framing, lighting or pose returns 400 with softIssues — resubmit with confirmLowFraming to accept the lower confidence.

Neither is billed. A capture we could not measure is ours to explain, not yours to pay for.

Limits

PlanLive scans / monthRequests / minLive keys
free30sandbox only
trial30sandbox only
home60sandbox only
home_plus60sandbox only
business2000300yes

Live API access is part of the Business plan. Every plan can use test keys without limit on allowance. Check your own numbers any time with GET /api/v1/account.

Errors

Every failure returns a stable code and a requestId. Branch on the code — the message is for humans and may be reworded. Quote the requestId in any support request.

CodeHTTPMeaning
missing_api_key401No API key was supplied. Send Authorization: Bearer forma_live_…
malformed_api_key401That does not look like a FORMA key. Keys begin forma_live_ or forma_test_.
invalid_api_key401The API key is not recognised.
revoked_api_key401That API key has been revoked.
plan_required403Your plan does not include live API access.
quota_exceeded429Monthly scan allowance used up.
rate_limited429Too many requests. Slow down and retry.
invalid_request400The request body or parameters were not valid.
payload_too_large413The frame is larger than this plan allows.
not_found404No such resource.
scan_quality_too_low422The capture was not good enough to measure.
store_unavailable503The durable store is unreachable, so this request cannot be recorded.
internal_error500Something went wrong on our side.

Machine-readable at /api/v1/errors.

Reference

  • OpenAPI 3.1 specification — import into Postman or generate a client
  • GET /api/v1/account — plan, limits and usage
  • GET /api/v1/usage — allowance used this period
  • GET /api/v1/scans?profileId=… — history for a profile
  • GET /api/v1/scans/{id} — one scan with landmarks and mesh

Business allowance is 2000 live scans a month at 300 requests a minute.

Talk to us

API access is $299/month for 2,000 live scans. Higher volume is priced per use case — tell us what you are building and we will size it.

Something broken? Report it here and include the requestId from the response — it identifies the exact request in our logs and turns a guessing game into a lookup.

You can build the entire integration on a sandbox key before speaking to anyone. That is deliberate: we would rather you knew it worked first.