---
title: Authentication — Americans Home Sleep API
description: How an agent obtains and uses a credential for the Americans Home API. Reads need none; writes take a self-serve bearer token issued instantly.
canonical: https://americanshomeqa.com/mattress-finder/auth.md
last-updated: 2026-09-09
---

# Authentication

**Read this line first: every GET on this API is public and needs no credential.**
Firmness guidance, Qatar bed dimensions, pricing, and the FAQ are all open. If
you only need to read, stop here and call the endpoint.

Authentication applies to the two `POST` endpoints that create records:
`https://americanshomeqa.com/mattress-finder/api/v1/shortlists` and `https://americanshomeqa.com/mattress-finder/api/v1/reports`. Everything below is about those.

## Discover

Machine-readable metadata:

| Document | URL |
|---|---|
| Protected-resource metadata (RFC 9728) | `https://americanshomeqa.com/mattress-finder/.well-known/oauth-protected-resource` |
| Authorization-server metadata (RFC 8414) | `https://americanshomeqa.com/mattress-finder/.well-known/oauth-authorization-server` |
| OpenAPI description | `https://americanshomeqa.com/mattress-finder/openapi.json` |

Calling a protected endpoint without a token returns `401` with a spec-shaped
challenge, so you can also discover the requirement from any single request:

```
WWW-Authenticate: Bearer realm="Americans Home",
  resource_metadata="https://americanshomeqa.com/mattress-finder/.well-known/oauth-protected-resource"
```

The `agent_auth` block in the authorization-server metadata carries
`identity_endpoint` and `identity_types_supported`.

## Pick a method

`identity_types_supported` is `["anonymous"]`. There is one method and it is
the simplest one that exists: ask for a key, receive a key.

This service does **not** support `identity_assertion` (including the ID-JAG
token type `urn:ietf:params:oauth:token-type:id-jag`) or `service_auth`. Those
are deliberately absent rather than unimplemented — advertising an assertion
type we cannot verify would send you down a minting path that fails at the last
step.

## Register

`POST https://americanshomeqa.com/mattress-finder/api/v1/keys`. No account, no email, no approval, no waiting list.

```bash
curl -X POST https://americanshomeqa.com/mattress-finder/api/v1/keys \
  -H 'Content-Type: application/json' \
  -d '{"mode":"test","label":"my agent"}'
```

```json
{
  "key": "ah_test_…",
  "mode": "test",
  "usage": { "header": "Authorization: Bearer ah_test_…" }
}
```

`mode` is `test` (default) or `live`:

- **`ah_test_…`** — sandbox. Writes are fully validated and echoed back, but
  nothing is persisted and the showroom is never contacted. Use this.
- **`ah_live_…`** — production. Writes reach the real showroom queue, and a
  callback request means a person gets phoned.

## Claim

There is no claim step. The key returned by `POST https://americanshomeqa.com/mattress-finder/api/v1/keys` is already
bound to you and already active; there is no separate activation, verification,
or claim exchange to perform.

If you want to skip registration entirely, the sandbox key **`ah_test_sandbox`**
is published, permanent, and always valid. It is not a secret. Its purpose is to
let you exercise the full write path — including its error cases — without a
registration round-trip you may not be able to complete unattended.

## Exchange

There is no exchange step either. The credential from the identity endpoint is
the credential you send; it is not swapped for a separate access token.

This is why `grant_types_supported` is `["client_credentials"]` and
`token_endpoint` and `registration_endpoint` are the same URL.

## Use the access_token

Send it as a bearer token:

```bash
curl -X POST https://americanshomeqa.com/mattress-finder/api/v1/shortlists \
  -H 'Authorization: Bearer ah_test_sandbox' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 4f1c…' \
  -d '{"outcomeId":"side-sleeper-sleeps-hot-60-90kg","mattressIds":["m-cloud-soft"]}'
```

Always send `Idempotency-Key` on a write. If you retry after a network failure
with the same key, you get the original response back and no second record is
created. Without it, a retry a person can't see can result in two callbacks.

## Errors

Errors are JSON. Branch on `error.code`, never on the message text.

| Status | `error.code` | Meaning | What to do |
|---|---|---|---|
| 401 | `missing_credential` | No `Authorization` header | Send a bearer token. The 401 body names the sandbox key. |
| 401 | `invalid_credential` | Token unknown or revoked | Mint a new key at `https://americanshomeqa.com/mattress-finder/api/v1/keys`. |
| 400 | `invalid_body` | Body was not valid JSON | Fix the JSON. |
| 422 | `invalid_body` | A field failed validation | Read `error.parameter` and `error.allowedValues`. |
| 400 | `invalid_parameter` | A query parameter was wrong | `error.allowedValues` lists what is accepted. |
| 413 | `batch_too_large` | Over 50 batch operations | Split the batch. |

Every error body also carries RFC 9457 `type`, `title`, `status`, and
`detail` fields, so a client written against problem-details can read it too.

A `401` always includes the `WWW-Authenticate` challenge shown above, and its
body names the public sandbox key — so an unauthenticated attempt tells you
everything needed to retry successfully.

## Revocation

Keys do not expire on a timer. To revoke one, simply stop using it: keys are
held in memory and are dropped when the service restarts, so no key outlives a
deployment. Nothing you can create with one is durable either.

To revoke a key you believe is compromised, email hello@americanshome.qa. Because the
sandbox key is public by design, it cannot be compromised and is never revoked.

## Rate limits

`RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`
are returned on every response so you can pace yourself without probing for the
ceiling. A `429` would carry `Retry-After`; honour it.

## See also

- [API index](https://americanshomeqa.com/mattress-finder/api/v1) — every endpoint, with examples
- [OpenAPI description](https://americanshomeqa.com/mattress-finder/openapi.json)
- [Developer portal](https://americanshomeqa.com/mattress-finder/developers)
- Spec this document follows: <https://github.com/workos/auth.md>
