Latch Quick Start

Prerequisites

Get an API key from solenoid.systems/pricing. Keys are prefixed with sm_ and work across all Solenoid products.

All endpoints require a Bearer token. See Authentication.

Base URL

https://api.solenoid.systems

Acquire a Lock

curl -X POST "https://api.solenoid.systems/v1/latch/deploy:prod/acquire" \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"ttl": 10000, "timeout": 10000}'
const res = await fetch('https://api.solenoid.systems/v1/latch/deploy:prod/acquire', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sm_your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ ttl: 10000, timeout: 10000 })
})
const { token } = await res.json()

Response:

{
  "status": "acquired",
  "token": "550e8400-e29b-41d4-a716-446655440000",
  "expires_at": 1234567890,
  "key": "deploy:prod",
  "reentrant": false
}

Release a Lock

Pass the token from the acquire response.

curl -X POST "https://api.solenoid.systems/v1/latch/deploy:prod/release" \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"token": "550e8400-e29b-41d4-a716-446655440000"}'
await fetch('https://api.solenoid.systems/v1/latch/deploy:prod/release', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sm_your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ token: '550e8400-e29b-41d4-a716-446655440000' })
})

Response:

{ "status": "released" }

Check Lock Status

curl "https://api.solenoid.systems/v1/latch/deploy:prod" \
  -H "Authorization: Bearer sm_your_api_key_here"

Response:

{
  "locked": true,
  "queue_depth": 3,
  "ttl_remaining": 25000
}

Reentrant Locking

Re-acquire with the same token to refresh the TTL without releasing. Useful for long-running jobs.

const res = await fetch('https://api.solenoid.systems/v1/latch/job:123/acquire', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sm_your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ ttl: 10000, timeout: 10000 })
})
const { token } = await res.json()

// ... do work ...

// Refresh TTL without releasing
await fetch('https://api.solenoid.systems/v1/latch/job:123/acquire', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sm_your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ ttl: 10000, timeout: 0, token })
})

Waiting Behavior

When you request a held lock, the HTTP connection stays open until one of:

  • Lock freed — you receive a 200 with your token
  • Timeout reached — you receive a 408
  • Queue full — you receive a 429 (100+ waiters already queued)

This is not polling. The request hangs and completes immediately when the lock is freed.

Next Steps