# Fixture tokens

A fixture token lets a test run create and delete test data through a deployment's Fixture API: routes in the product that make the records its tests need. Clanker Ship signs each token as an EdDSA JWT for one scope and one Fixture API, which verifies it against `GET /.well-known/jwks.json`. Starting a run or a retry returns one; create one here to test without publishing a run.

## The FixtureGrant object

A scope and the fixture token that lets a test run create and delete data in it.

### Attributes

- `scope` (string, required): The scope's ID: `scp_` and 12 lowercase letters or digits, such as scp_7h2k9q2m4x1a.
- `token` (string, required): The fixture token: an EdDSA JWT that only `url` accepts, for this scope only. Send it as `Authorization: Bearer …` to the Fixture API.
- `url` (string, required): The Fixture API to call.
- `expiresAt` (string, required): When the token and the scope expire, as an ISO 8601 timestamp.

### Example

```json
{
  "scope": "scp_7h2k9q2m4x1a",
  "token": "eyJhbGciOiJFZERTQSIsImtpZCI6ImZ4XzEifQ.eyJzY29wZSI6InNjcF83aDJrOXEybTR4MWEifQ.c2lnbmF0dXJl",
  "url": "https://staging.acme.dev/fixtures",
  "expiresAt": "2026-10-14T15:40:00.000Z"
}
```

## Create a fixture token

`POST /v1/workspaces/{slug}/deployments/{product}/{environment}/fixture-tokens`

Returns a new scope and fixture token for a deployment's Fixture API without starting a run, for unpublished runs and conformance checks. Viewers cannot create one, and a deployment without a Fixture API fails the request unless `fixtureUrl` names one.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `product` (string, in path, required): The product's slug, such as storefront.
- `environment` (string, in path, required): The environment's slug, such as staging.
- `lifetimeSeconds` (number): How long the token and scope last, in whole seconds, from 5 to 21600 (six hours, the default).
- `fixtureUrl` (nullable string): Use this Fixture API instead of the deployment's, such as a local server on another port. The fixture token is only valid there.

### Returns

Returns the [FixtureGrant](https://docs.qa.clankership.net/api/fixture-tokens/object.md) object. The status is 201.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/deployments/{product}/{environment}/fixture-tokens \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lifetimeSeconds": 600
  }'
```

### Response

```json
{
  "scope": "scp_7h2k9q2m4x1a",
  "token": "eyJhbGciOiJFZERTQSIsImtpZCI6ImZ4XzEifQ.eyJzY29wZSI6InNjcF83aDJrOXEybTR4MWEifQ.c2lnbmF0dXJl",
  "url": "https://staging.acme.dev/fixtures",
  "expiresAt": "2026-10-14T15:40:00.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.
