# Quickstart

# Quickstart

Every path in the API is absolute. The examples below use `$WER_API_BASE` for
the base URL, you will use one of:
- https://api.we-r.com (production)
- https://api-dev.we-r.com (staging)

## Get your credentials

WeR issues API credentials for you, one set per environment.

Email **api-access@we-r.com** with your organisation's legal name, a named
technical contact at your own domain, and whether you want non-production or
production access. WeR replies with your `client_id` by email, and your
`client_secret` through a single-use link that expires in 24 hours.

Open that link once and store the secret in an appropirate secret management infrastructure. 
WeR keeps only a hash of secrets and cannot send it to you again — if you
lose it, ask for a rotation and you will get a new secret against the same
`client_id`.

Your credentials are bound to exactly one organisation's data, and your
non-production credentials do not work against production.

## Exchange the credentials for a token

[`POST /auth/token`](/reference/auth#exchange-client-credentials-for-an-access-token)
is a standard OAuth 2.0 client-credentials exchange, so an off-the-shelf OAuth
client works against it unchanged.

**The request body is `application/x-www-form-urlencoded`, not JSON.** This is
the one endpoint in the API that does not take JSON. Posting a JSON body here
fails validation.

```bash
curl -sS -X POST "$WER_API_BASE/auth/token" \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode "client_id=$WER_CLIENT_ID" \
  --data-urlencode "client_secret=$WER_CLIENT_SECRET"
```

You get back `access_token`, `token_type` (always `Bearer`), and `expires_in`
— the token's remaining lifetime in seconds. The full shape is in
[the reference](/reference/auth#exchange-client-credentials-for-an-access-token/responses).

The contract does not fix a lifetime, so **there is no number to hard-code**.
Read `expires_in` off the response and re-exchange before it elapses. Leave a margin of 
at least a minute where possible.

Simplified JS example:

```js
const tokenUrl = `${process.env.WER_API_BASE}/auth/token`;

async function fetchToken() {
  const response = await fetch(tokenUrl, {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.WER_CLIENT_ID,
      client_secret: process.env.WER_CLIENT_SECRET,
    }),
  });

  if (!response.ok) {
    const { errors } = await response.json();
    throw new Error(`token exchange failed (${response.status}): ${errors[0].code}`);
  }

  const token = await response.json();
  return { accessToken: token.access_token, renewAfter: Date.now() + (token.expires_in - 60) * 1000 };
}
```

The token is opaque. Do not parse it, and do not assume it is a JWT — the
contract says only that it is a string.

A token is valid for one organisation, and revoking a credential takes effect
immediately, so treat a sudden 401 as "get a new token, then retry"
rather than as a transient fault.

### 400 here, 422 everywhere else

The two `/auth` endpoints return **400** when a request fails validation, following the OAuth spec.
Our other `/v1` endpoints return validation failures as **422**. Branch on the `code` 
inside the `errors` array, not on 400 versus 422 alone. Every error response in 
the API has that same shape: an `errors` array of `{code, message}` objects.

## Make the first read

Reads carry the token as `Authorization: Bearer <token>`.

[`GET /v1/inspiration`](/reference/inspiration#look-up-ready-made-content)
returns your organisation's ready-made content for one segment, use case and
locale. All three are required, so start by listing the first two:

```bash
curl -sS "$WER_API_BASE/v1/segments" -H "Authorization: Bearer $WER_TOKEN"
curl -sS "$WER_API_BASE/v1/use-cases" -H "Authorization: Bearer $WER_TOKEN"
```

[`GET /v1/segments`](/reference/segments#list-your-segments) gives you the
segments set up for content generation, and
[`GET /v1/use-cases`](/reference/use-cases#list-the-available-use-cases) the
kinds of content you can ask for. Take an `id` from each.

```bash
curl -sS -G "$WER_API_BASE/v1/inspiration" \
  -H "Authorization: Bearer $WER_TOKEN" \
  --data-urlencode "segment_id=$SEGMENT_ID" \
  --data-urlencode "use_case_id=$USE_CASE_ID" \
  --data-urlencode 'locale=en-GB'
```

A successful read returns a collection holding a suggestion-set: the
newest suggestions for that segment, use case and locale, with its variants in
`data[0].suggestions`. Pass `version` to fetch an earlier one instead. The
[query parameters](/reference/inspiration#look-up-ready-made-content/query-parameters)
and the
[response](/reference/inspiration#look-up-ready-made-content/responses) are in
the reference.

## Expect an empty result first

Your first read will very likely return a 200 with an empty `data` array:

```json
{ "data": [], "meta": { "next_cursor": null } }
```

You will hit this on day one because a new organisation has nothing generated
yet. Ready-made content is produced in the background overnight, so there is a window
between your credentials working and there being anything to read.

If you want content now rather than waiting for the schedule, ask for it with
[`POST /v1/inspiration`](/reference/inspiration#generate-ready-made-content-again)
to force generation and read `GET /v1/inspiration` again in a few minutes.

## Where to go next

- **[Steering and refinement](/guides/steering-and-refinement)** — generating
  content from your own instructions, polling the run, and refining what comes
  back. Note that creating a generation run needs user-level authentication; an 
  access token from this page cannot do it.
- **[Asset URLs](/guides/asset-urls)** — turning the opaque image references
  inside a suggestion into URLs you can load.
- **[Versioning and deprecation](/guides/versioning-and-deprecation)** — what
  WeR can change inside a `/v1` endpoint without notice periods.
