This API returns data, not copy. No pre-written sentences, no branded language — you control how results are presented to your own users; we control the accuracy of the underlying analysis.
Authentication
All requests require a bearer API key:sk_test_...) run the full pipeline against non-billed, non-persisted requests — use them for integration testing.
API keys and webhook signing secrets are provisioned during onboarding. Once your account is set up, your HairHealth.ai account manager will issue your live and test keys. Sandbox credentials are available on request if you’d like to integrate against this spec before your account is fully live.
Base URL
Your base URL will be provided by HairHealth.ai in your onboarding document, along with your API key and webhook signing secret.
/v1/hairscan) are relative to that base URL. The API is versioned in the path; breaking changes will ship as /v2, additive changes (new optional fields) will not change the version.
The scan object
This is the core object returned once a scan completes.| Field | Type | Description |
|---|---|---|
scan_id | string | Unique identifier for this scan |
status | enum | processing, complete, or failed |
created_at | timestamp | ISO 8601 |
completed_at | timestamp | ISO 8601 |
Echoes the subject info submitted with the scan
Overall score, band, confidence, and 3 pillar scores
Notable findings worth surfacing to a user or clinician. No narrative — pair these with your own copy in your UI.
Four fixed scalp regions, each rated
low / medium / high with an optional tagFull detailed metrics, grouped into 2 categories
Structured, not diagnostic language — a data label, not a report sentence
Top 3 ranked SKU matches — present only if a product catalog has been onboarded for your account
Compact record for CRM/lead routing
Endpoints
Create a scan
JSON string — see
subject schema aboveClear frontal hairline photo
Top-down crown photo — recommended, needed for crown flags & density
Improves hairline recession accuracy
Back/sides — needed for donor region reading
Free-form JSON object, e.g.
family_history, onset_duration_months. Exact fields are configured per account — talk to your account manager to set up your intake schema.Overrides your account’s default webhook URL for this scan
202 Accepted, returned immediately:
Retrieve a scan
Webhooks
Instead of polling, register awebhook_url on your account (or per-request) to be notified when a scan completes.
event is hairscan.completed or hairscan.failed.
Errors
Errors return a standard shape:| HTTP status | type |
|---|---|
| 400 | invalid_request_error |
| 401 | authentication_error |
| 404 | not_found_error |
| 422 | processing_error (e.g. image quality) |
| 429 | rate_limit_error |
| 500 | api_error |
message is for developers/logs — don’t surface it directly to end users.Rate limits
Each API key has a request quota tied to your account’s plan. Every response includes:429 with type: rate_limit_error.
Changelog
- v1 — initial release.