# Asset URLs

Asset URLs, such as images, are not returned by default by the API. This is due
to them having a 15 minute expiry window for security purposes. If you were
to store a URL, it would quickly become un-loadbale. Instead, assets arrive as
references, and you exchange a reference for a short-lived URL at the moment
you need to display it.

## Asset references

An image appears inside a suggestion's `payload` as an asset with a `ref`, 
for example `"ref": "image:019a9634-bcf0-7a92-b6e0-7b1d48f35026"`

You can safely store it as a string, there shoudl be no need to parse or split it. 
The reference is a durable identifier and is accepted by both resolution calls below.

Alongside `ref`, an asset carries `alt_text` for accesibility.

## Two ways to get a time-bound image URL

### At read time

[`GET /v1/inspiration`](/reference/inspiration#look-up-ready-made-content)
takes an `expand` query parameter. Pass `asset_urls` and every
image in the response comes back with `url` and `url_expires_at` filled in.
This is used when you are not caching ort storing results from WeR, and 
are immidately displaying them to users.

```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' \
  --data-urlencode 'expand=asset_urls'
```

One limitation: **`expand=asset_urls` exists only on `/inspiration` today, it is not yet available on
[`GET /v1/suggestion-sets/{suggestionSetId}`](/reference/suggestion-sets#fetch-a-suggestion-set-by-id), 
[`GET /v1/suggestion-sets`](/reference/suggestion-sets#list-suggestion-sets),
or [`GET /v1/suggestions/{suggestionId}`](/reference/suggestions#fetch-a-single-suggestion-by-id).
This will be added soon, if you are blocked, please get in touch. Until that point, the below URL can be used.

### From a stored ref: `POST /v1/assets/urls`

[`POST /v1/assets/urls`](/reference/assets#get-loadable-urls-for-images) takes
a `refs` array and returns one URL per reference, each with its own
`url_expires_at`. Between one and a hundred references per call.

```bash
curl -sS -X POST "$WER_API_BASE/v1/assets/urls" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $WER_TOKEN" \
  -d '{"refs": ["image:5f6b2f0c-1c2a-4f5e-9a4d-6b1c2e3f4a5b"]}'
```

If any reference is malformed, unknown, or belongs to another organisation, 
the whole call fails. Ensure you only use refs you stored to avoid issues

## Expiry

Resolved URLs are short-lived by design, the response carries `url_expires_at` 
— an exact timestamp for when that URL stops working. After this you must mint a new URL.

To avoid issues, ensure you:

**Resolve a URL at the moment you display.** The clock starts when the URL is minted.

**Never cache a URL beyond its own `url_expires_at`.**

**Never store a URL as if it were permanent.** Do not write one into a
database row, a content-management field, a sent email, a scheduled social
post, or an export a customer downloads later. For these usecases, save your 
own copy of an image.

### Handling expiry

When a URL expires — you would get an error from the storage host rather than 
from this API, so the failure surfaces as a broken image, not as an API 
response you can branch on. There is no refresh operation: you must
call `POST /v1/assets/urls` again with the same `ref` and get a new URL with a
new expiry.

Practically, that means your render path needs the `ref` in hand at the point
of display, not just the URL. A component that receives only a URL has no way
back. Pass both, or pass the `ref` and resolve inside.

## In summary

- **Displaying content now** — use `expand=asset_urls`. One request instead of two.
- **Rendering from references you stored** — use `POST /v1/assets/urls`.
- **Reading but not displaying** — do not pass `expand`, store refs if required for later display.
