Search the docs

Search guides, API endpoints and MCP tools.

Semaphore leases

A lease is one held slot on a semaphore. A test takes one around the part that uses the shared resource, renews it while it works and releases it when done; a lease that is not renewed ends after its TTL, so a test that dies frees its slot. Leases take the run token that starting a run, a shard or a retry returns as semaphores.token, not an API key, and semaphores.url is where their routes start. An unpublished run has no run token, so it holds none.

The SemaphoreLease object

One held slot on a semaphore, until it is released, expires or its holder finishes.

Attributes

leasestringRequired

The lease's ID. Renew and release the lease by it.

semaphorestringRequired

The semaphore's name.

expiresAtstringRequired

When the lease ends unless it is renewed, as an ISO 8601 timestamp. Its slot frees itself then.

The SemaphoreLease object
{  "lease": "Ls4TnV8qWm2C",  "semaphore": "payments-sandbox",  "expiresAt": "2026-10-14T09:41:20.000Z"}

Take a lease

POST/v1/workspaces/{slug}/semaphores/{name}/leases

Takes a slot on the semaphore, creating it with capacity on first use. When every slot is held, the request waits up to 20 seconds for one to free, then fails with Busy and retryAfter; ask again until your own timeout. Another capacity than the semaphore's fails with Conflict. The lease belongs to the shard or retry whose run token took it, and finishing that shard or retry releases it.

Path parameters

slugstringRequired

The workspace's slug or ID, such as acme.

namestringRequired

The semaphore's name, such as payments-sandbox: 1 to 100 lowercase letters, digits, dots, underscores or hyphens, starting with a letter or digit.

Body parameters

capacitynumberRequired

How many leases the semaphore allows at once, 1 to 100. The first lease creates the semaphore with it; every later lease must send the same.

ttlSecondsnumber

How long the lease lasts from now, in whole seconds, from 5 to 600; 60 by default. Renew it every third of that.

testnullable string

The test taking the lease, as members see it on the semaphore, up to 200 characters.

Returns

Returns the SemaphoreLease object. Status 201.

Errors

400
InvalidInputThe request is malformed, or a value is not allowed.
401
UnauthorizedThe request has no valid API key.
403
ForbiddenThe key's user or role may not do this.
404
NotFoundThe workspace or object does not exist, or the caller cannot see it.
409
The change conflicts with current data, such as a slug that is already in use.
500
InternalClanker Ship failed to handle the request. Retry, or report the response's x-request-id.
POST/v1/workspaces/{slug}/semaphores/{name}/leases
curl -X POST https://api.clankership.com/v1/workspaces/acme/semaphores/{name}/leases \  -H "Authorization: Bearer $CLANKER_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "capacity": 1,    "ttlSeconds": 60,    "test": "checkout › applies a coupon"  }'
Response201
{  "lease": "Ls4TnV8qWm2C",  "semaphore": "payments-sandbox",  "expiresAt": "2026-10-14T09:41:20.000Z"}

Renew a lease

POST/v1/workspaces/{slug}/semaphores/{name}/leases/{lease}/renew

Extends a lease to ttlSeconds from now and returns its new expiry. A lease that was released or expired, or that another run holds, fails with NotFound: take a new one.

Path parameters

slugstringRequired

The workspace's slug or ID, such as acme.

namestringRequired

The semaphore's name, such as payments-sandbox: 1 to 100 lowercase letters, digits, dots, underscores or hyphens, starting with a letter or digit.

leasestringRequired

The lease's ID, from taking it.

Body parameters

ttlSecondsnumber

How long the lease lasts from now, in whole seconds, from 5 to 600; 60 by default. Renew it every third of that.

Returns

Returns the SemaphoreLease object. Status 200.

Errors

400
InvalidInputThe request is malformed, or a value is not allowed.
401
UnauthorizedThe request has no valid API key.
403
ForbiddenThe key's user or role may not do this.
404
NotFoundThe workspace or object does not exist, or the caller cannot see it.
409
ConflictThe change conflicts with current data, such as a slug that is already in use.
500
InternalClanker Ship failed to handle the request. Retry, or report the response's x-request-id.
POST/v1/workspaces/{slug}/semaphores/{name}/leases/{lease}/renew
curl -X POST https://api.clankership.com/v1/workspaces/acme/semaphores/{name}/leases/{lease}/renew \  -H "Authorization: Bearer $CLANKER_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "ttlSeconds": 60  }'
Response200
{  "lease": "Ls4TnV8qWm2C",  "semaphore": "payments-sandbox",  "expiresAt": "2026-10-14T09:41:20.000Z"}

Release a lease

DELETE/v1/workspaces/{slug}/semaphores/{name}/leases/{lease}

Frees the lease's slot for the next test. Releasing a lease that already ended succeeds too.

Path parameters

slugstringRequired

The workspace's slug or ID, such as acme.

namestringRequired

The semaphore's name, such as payments-sandbox: 1 to 100 lowercase letters, digits, dots, underscores or hyphens, starting with a letter or digit.

leasestringRequired

The lease's ID, from taking it.

Returns

Returns no content. Status 204.

Errors

400
InvalidInputThe request is malformed, or a value is not allowed.
401
UnauthorizedThe request has no valid API key.
403
ForbiddenThe key's user or role may not do this.
404
NotFoundThe workspace or object does not exist, or the caller cannot see it.
409
ConflictThe change conflicts with current data, such as a slug that is already in use.
500
InternalClanker Ship failed to handle the request. Retry, or report the response's x-request-id.
DELETE/v1/workspaces/{slug}/semaphores/{name}/leases/{lease}
curl -X DELETE https://api.clankership.com/v1/workspaces/acme/semaphores/{name}/leases/{lease} \  -H "Authorization: Bearer $CLANKER_API_KEY"