Multi-language Examples
Reserve and unreserve from curl, Python, Node.js, Go, and C#. No SDK required — it's just HTTP.
curl
Reserve
curl -X POST https://cooplocker.com/api/v1/Reservation/reserve \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"requester":"my-app","resource":"my-lock","ttlSeconds":60}]'
Unreserve
curl -X POST https://cooplocker.com/api/v1/Reservation/unreserve \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"requester":"my-app","resource":"my-lock","releaseToken":"TOKEN_FROM_RESERVE"}]'
Check
curl https://cooplocker.com/api/v1/Reservation/check/my-lock \ -H "X-Api-Key: YOUR_API_KEY"
Python (requests)
No SDK needed — the standard requests library is all you need.
Reserve
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://cooplocker.com/api/v1"
HEADERS = {"X-Api-Key": API_KEY, "Content-Type": "application/json"}
resp = requests.post(
f"{BASE}/Reservation/reserve",
headers=HEADERS,
json=[{"requester": "my-app", "resource": "my-lock", "ttlSeconds": 60}],
)
resp.raise_for_status()
results = resp.json()
result = results[0]
print(result["status"]) # "ACQUIRED"
token = result["releaseToken"] # save this
Unreserve
resp = requests.post(
f"{BASE}/Reservation/unreserve",
headers=HEADERS,
json=[{
"requester": "my-app",
"resource": "my-lock",
"releaseToken": token,
}],
)
resp.raise_for_status()
print(resp.json()[0]["status"]) # "RELINQUISHED"
Node.js (native fetch)
Requires Node.js 18+. No additional packages needed.
Reserve
const API_KEY = "YOUR_API_KEY";
const BASE = "https://cooplocker.com/api/v1";
const headers = { "X-Api-Key": API_KEY, "Content-Type": "application/json" };
const reserveResp = await fetch(`${BASE}/Reservation/reserve`, {
method: "POST",
headers,
body: JSON.stringify([
{ requester: "my-app", resource: "my-lock", ttlSeconds: 60 }
]),
});
if (!reserveResp.ok) throw new Error(`Reserve failed: ${reserveResp.status}`);
const [result] = await reserveResp.json();
console.log(result.status); // "ACQUIRED"
const token = result.releaseToken; // save this
Unreserve
const unreserveResp = await fetch(`${BASE}/Reservation/unreserve`, {
method: "POST",
headers,
body: JSON.stringify([
{ requester: "my-app", resource: "my-lock", releaseToken: token }
]),
});
if (!unreserveResp.ok) throw new Error(`Unreserve failed: ${unreserveResp.status}`);
const [unreserveResult] = await unreserveResp.json();
console.log(unreserveResult.status); // "RELINQUISHED"
Go (net/http)
Reserve
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
const apiKey = "YOUR_API_KEY"
const base = "https://cooplocker.com/api/v1"
func reserve(requester, resource string, ttl int) (string, error) {
body, _ := json.Marshal([]map[string]any{
{"requester": requester, "resource": resource, "ttlSeconds": ttl},
})
req, _ := http.NewRequest("POST", base+"/Reservation/reserve", bytes.NewReader(body))
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var results []map[string]any
json.NewDecoder(resp.Body).Decode(&results)
token, _ := results[0]["releaseToken"].(string)
fmt.Println("status:", results[0]["status"])
return token, nil
}
Unreserve
func unreserve(requester, resource, token string) error {
body, _ := json.Marshal([]map[string]any{
{"requester": requester, "resource": resource, "releaseToken": token},
})
req, _ := http.NewRequest("POST", base+"/Reservation/unreserve", bytes.NewReader(body))
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
var results []map[string]any
json.NewDecoder(resp.Body).Decode(&results)
fmt.Println("status:", results[0]["status"])
return nil
}
C# (HttpClient)
Reserve
using System.Net.Http.Json;
var client = new HttpClient();
var apiKey = "YOUR_API_KEY";
var baseUrl = "https://cooplocker.com/api/v1";
client.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
var payload = new[]
{
new { requester = "my-app", resource = "my-lock", ttlSeconds = 60 }
};
var response = await client.PostAsJsonAsync($"{baseUrl}/Reservation/reserve", payload);
response.EnsureSuccessStatusCode();
var results = await response.Content.ReadFromJsonAsync<List<ReservationResult>>();
var token = results![0].ReleaseToken;
Console.WriteLine(results[0].Status); // ACQUIRED
record ReservationResult(string Resource, string Requester, string Status,
string Explanation, string? ReleaseToken);
Unreserve
var release = new[]
{
new { requester = "my-app", resource = "my-lock", releaseToken = token }
};
var resp = await client.PostAsJsonAsync($"{baseUrl}/Reservation/unreserve", release);
resp.EnsureSuccessStatusCode();
var releaseResults = await resp.Content.ReadFromJsonAsync<List<ReservationResult>>();
Console.WriteLine(releaseResults![0].Status); // RELINQUISHED
Conflict strategy examples
Use POST /api/v1/Reservation/transactions when you need atomic
multi-resource semantics. Pass one or more transaction objects, each with a
method and a list of requests.
ALL_OR_NONE — both locks or nothing
curl -X POST https://cooplocker.com/api/v1/Reservation/transactions \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{
"method": "ALL_OR_NONE",
"requestType": "RESERVE",
"requests": [
{"requester":"svc-a","resource":"db-primary"},
{"requester":"svc-a","resource":"db-replica"}
]
}]'
If db-replica is held, neither lock is acquired and the transaction rolls back.
FIRST — claim the first available worker slot
curl -X POST https://cooplocker.com/api/v1/Reservation/transactions \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{
"method": "FIRST",
"requestType": "RESERVE",
"requests": [
{"requester":"job-99","resource":"worker-1"},
{"requester":"job-99","resource":"worker-2"},
{"requester":"job-99","resource":"worker-3"}
]
}]'
Claims the first available worker and stops — no need to check which one is free first.
AS_MANY_AS_POSSIBLE — grab every available slot
curl -X POST https://cooplocker.com/api/v1/Reservation/transactions \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{
"method": "AS_MANY_AS_POSSIBLE",
"requestType": "RESERVE",
"requests": [
{"requester":"batch-runner","resource":"slot-A"},
{"requester":"batch-runner","resource":"slot-B"},
{"requester":"batch-runner","resource":"slot-C"}
]
}]'
Acquires whichever slots are free and skips the rest — useful for bulk claiming.