Skip to content
ShirtMath
FOR BRANDS

Fit API reference

The ShirtMath fit API is two browser calls: post a publishable key to /b2b/widget/session for a short-lived signed session, then post a product and the shopper's reference garment to /b2b/widget/match for a recommended size.

Last verified: 26 August 2026

The ShirtMath fit API is two browser calls and one server-side family. You post a publishable key to /b2b/widget/session to get a short-lived signed session, then post a product reference and a shopper's reference garment to /b2b/widget/match to get a recommended size, an explanation, and a candidate list. Everything else lives under the workspace endpoints, scoped to your business id.

This page documents the endpoints that exist on the running service today. Where a field list, an error code or a numeric limit is not published here, it is because it is settled at integration time and this page will not guess at it. ShirtMath is pre-launch; treat every shape below as documented but young.

What is the ShirtMath fit API?

It is a garment-to-garment matching service. Your product catalogue carries flat measurements. The shopper supplies a reference garment they already own and like. The API compares the two sets of measurements and returns the size on your product that lands closest, with the reasoning attached.

It does not scan bodies and it does not estimate a body from a photograph. The comparison is garment against garment, which is why the answer can be explained in numbers rather than asserted. If you have not imported a catalogue yet, start at connect your catalogue; the matching endpoints have nothing to match against until products exist.

How does authentication work?

There are two credential types and they are not interchangeable.

CredentialWhere it belongsHeader
Publishable keyBrowser, storefront markupX-ShirtMath-Key
Session tokenBrowser, returned by the session callX-ShirtMath-Session
Secret keyServer only, shown once at creationDocumented at integration time

A secret key is displayed once, at the moment it is created, and is not retrievable afterwards. If it is lost, rotate it. Rotation and revocation are separate operations on purpose: rotation issues a replacement so you can cut over, revocation kills a key outright.

  1. Create a key — POST to /b2b/workspace/{business_id}/keys. The secret half is shown once in that response.
  2. Verify a domain — register the storefront origin, then confirm it through /b2b/workspace/{business_id}/domains/verify.
  3. Open a session — POST /b2b/widget/session with the publishable key in X-ShirtMath-Key. A domain in verified state is granted CORS; anything else is not.
  4. Match — POST /b2b/widget/match with the session token in X-ShirtMath-Session.
  5. Rotate or revoke/b2b/workspace/{business_id}/keys/{key_id}/rotate and /revoke when a key leaks or a contractor leaves.

How does domain verification restrict origins?

The session endpoint grants cross-origin access only to a domain your workspace holds in verified state. A publishable key on its own is not enough. That is the point of the pair: the key is public by design, so the origin restriction is what stops a copied key from working on someone else's site.

Domains are managed at /b2b/workspace/{business_id}/domains and moved to verified through /b2b/workspace/{business_id}/domains/verify. The verification method and its record format are handed over during onboarding rather than published here.

What does POST /b2b/widget/session return?

A short-lived signed session, intended to be held in the page and used for the match calls that follow. It is short-lived deliberately, so a token scraped from a page stops working quickly. The exact lifetime is set per tenant and confirmed at integration time.

What does POST /b2b/widget/match do?

It takes the product the shopper is looking at and the garment they already own, and returns a size on your product. The request body carries two members.

Request memberMeaning
product_refYour own product id, as imported into the catalogue
referenceThe shopper's reference garment; the object's field list is fixed at integration time

The response carries five members that the widget renders directly.

Response memberWhat it holds
statusWhether an answer was produced, or the honest-failure value below
authorityWhich fit authority answered; values seen in the client include SANDBOX and PHASE4
current_productCarries recommended_size for the product the shopper is on
explanationThe reasoning behind the recommendation, for display
candidatesThe other sizes or products considered, as a list

Read authority before you trust a recommendation in a test environment. A SANDBOX answer is not a production answer, and a widget that renders the two identically will mislead whoever is doing the acceptance pass.

What happens when ShirtMath cannot answer?

The status member may come back as FIT_AUTHORITY_UNAVAILABLE. That is not an error to retry around and not a signal to fall back on a guess. It means the service does not hold enough measurement data to make a defensible comparison for that product, and the widget shows an honest "not enough information" instead.

The usual cause is missing measurements on your side rather than a fault on ours. Check /b2b/workspace/{business_id}/coverage, which reports measurement coverage across the imported catalogue, and fill the gaps at source.

Which workspace endpoints exist?

All of these are scoped to a business id. A credential issued to one workspace reaches that workspace's records and no other.

EndpointPurpose
/b2b/api/productsThe tenant's own imported products
/b2b/workspace/{business_id}The workspace record
/b2b/workspace/{business_id}/catalogThe imported catalogue
/b2b/workspace/{business_id}/coverageMeasurement coverage across that catalogue
/b2b/workspace/{business_id}/keysList and create keys
/b2b/workspace/{business_id}/keys/{key_id}/rotateIssue a replacement for one key
/b2b/workspace/{business_id}/keys/{key_id}/revokeKill one key
/b2b/workspace/{business_id}/domainsRegistered storefront domains
/b2b/workspace/{business_id}/domains/verifyMove a domain to verified state
/b2b/workspace/{business_id}/installInstall details for the storefront
/b2b/workspace/{business_id}/integrationIntegration configuration
/b2b/workspace/{business_id}/auditAudit record for the workspace

What does the browser widget do?

The client identifies itself as b2b-widget/0.1.0 and mounts into a host element on your product page. It opens a session, calls match when the shopper supplies a reference garment, and renders the recommended size with its explanation. The version string is worth logging on your side: a widget at 0.1.0 is early software and you will want to know which build produced a given answer.

What are the rate and permission boundaries?

Three boundaries are visible in the service as it runs today. First, origin: CORS is granted only to a verified domain. Second, scope: workspace endpoints are addressed by business id, so a key does not reach another tenant's catalogue. Third, credential separation: the browser only ever holds a publishable key and a short-lived session, never a secret key.

Numeric request limits, retry guidance and the error code table are set per tenant and confirmed during onboarding. They are not published on this page because publishing a number that later changes is worse than publishing nothing.

Why does garment measurement make the answer explainable?

Because the comparison is between two numbers rather than between two letters. Letters are not stable across cuts. In ShirtMath's held blank specifications, a ladies' Gildan G500L Medium publishes a 17.5" chest while the unisex Mediums publish 20.0" to 20.5" — a 3 inch gap on the same letter, and the same 3 inch gap at Large.

That gap is why an explanation member exists in the response at all. A shopper told "Large" learns nothing; a shopper told which measurement drove the answer can disagree with it intelligently. The same drift across brands is covered in the guide to vanity sizing, and the comparison logic itself is set out in the methodology.

What is not in this API?

Body scanning is not, in any form. Shoe identification and shoe fit from a photograph are not. Sunglasses measurement from a photograph is not. The live capability is a shirt laid flat with a scale card, measured from a photograph, matched against published garment measurements — roughly half of scanner readings land within an inch of a tape, sleeve opening and bicep are the least reliable, and anything the reader cannot resolve confidently is left blank rather than filled in.

Common questions

Do I need a secret key in the browser?
No. The browser holds a publishable key in X-ShirtMath-Key and the short-lived session token in X-ShirtMath-Session. Secret keys are server-side only and are shown once at creation.
What happens if ShirtMath cannot answer?
The status member returns FIT_AUTHORITY_UNAVAILABLE and the widget shows an honest "not enough information" message rather than a guess. Check the coverage endpoint for the missing measurements.
Can I call the widget endpoints from any domain?
No. CORS is granted only to a domain your workspace holds in verified state, which is why a copied publishable key does not work on another site.
Where are the full field lists documented?
The reference object's fields, the error code table and per-tenant limits are settled at integration time. This page documents the endpoints that exist and does not invent the details it cannot verify.

Where to go next

See the match logic from the shopper's side first. Photograph a shirt laid flat with a scale card and watch what the comparison actually says before you wire the widget into a product page.

Scan a shirt