# Record a deployment from CI

Tell Clanker Ship which build is running after every deploy, with one API call from your pipeline.

A deployment records where a product runs in one environment and which build is there. This example
sends the commit SHA to Clanker Ship after each production deploy of the storefront, so test runs
and people see what is running. It needs one `PATCH` request, so the deploy job does not need the
`clanker` CLI.

## Before you begin

You need an account API key with the member role, stored in your CI as `CLANKER_API_KEY`. See
[Publish test runs from CI](https://docs.qa.clankership.net/get-started/examples/publish-test-runs-from-ci.md#2-create-an-account-api-key)
for how to create one.

## 1. Create the deployment once

Each product has at most one deployment per environment. Create the storefront's production
deployment with its base URL, from your computer or a one-off job, with
[Create a deployment](https://docs.qa.clankership.net/api/deployments/create.md):

```bash
curl --fail-with-body https://api.clankertest.com/v1/workspaces/acme/deployments \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "product": "storefront", "environment": "production", "baseUrl": "https://shop.acme.dev" }'
```

Running it again fails with `409` and the message `Storefront is already deployed to Production.`,
so it is safe to keep in a setup script.

## 2. Record each deploy

After the deploy succeeds, send the new version with
[Update a deployment](https://docs.qa.clankership.net/api/deployments/update.md). Only `version` changes:

```bash
curl --fail-with-body -X PATCH \
  https://api.clankertest.com/v1/workspaces/acme/deployments/storefront/production \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{ \"version\": \"$GIT_SHA\" }"
```

The response is the deployment. The server sets `versionUpdatedAt` whenever the version changes:

```json
{
  "id": "Dp9LmT4kVx2R",
  "product": {
    "id": "Pr4GtY9sLm3B",
    "slug": "storefront",
    "name": "Storefront",
    "type": "website",
    "archived": false
  },
  "environment": {
    "id": "En1MwX6cTb7F",
    "slug": "production",
    "name": "Production",
    "class": "production",
    "emoji": null,
    "archived": false
  },
  "baseUrl": "https://shop.acme.dev",
  "fixtureUrl": null,
  "version": "4b7e0d2c91a35f8e6d0b7a2c4e1f9a8b3c5d6e7f",
  "versionUpdatedAt": "2026-10-14T09:05:12.000Z",
  "active": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

`version` is free text up to 100 characters, so a tag such as `v2.4.1` works as well as a SHA.

## In GitHub Actions

Add a step after your deploy step:

```yaml
- name: Record the deployment in Clanker Ship
  env:
    CLANKER_API_KEY: ${{ secrets.CLANKER_API_KEY }}
  run: |
    curl --fail-with-body -X PATCH \
      https://api.clankertest.com/v1/workspaces/acme/deployments/storefront/production \
      -H "Authorization: Bearer $CLANKER_API_KEY" \
      -H "Content-Type: application/json" \
      -d "{ \"version\": \"$GITHUB_SHA\" }"
```

`--fail-with-body` makes the step fail on an error and prints the error body, such as
`{"message":"Storefront is archived. Restore it before changing it or its deployments.","_tag":"Conflict"}`.
See [Errors](https://docs.qa.clankership.net/api/errors.md).

## With the CLI

When the job already has the `clanker` CLI, the same update is one command. It uses the workspace in
`clanker.json`, or `--workspace`:

```bash
clanker deployment update storefront production --deployed-version "$GITHUB_SHA"
```

## Variations

- **Move the base URL.** Send `baseUrl` in the same `PATCH`. Website and API products always need
  one; for other product types, `null` clears it.
- **Point test runs at a Fixture API.** Send `fixtureUrl` in the same `PATCH`, such as
  `https://shop.acme.dev/fixtures`, so each run makes its test data there. `null` clears it.
- **Record several environments.** Each environment has its own deployment:
  `PATCH /deployments/storefront/staging` after a staging deploy.
- **Let an agent do it.** Agents call [update_deployment](https://docs.qa.clankership.net/mcp/tools/update_deployment.md) with the
  same fields.
