Document / EN
Server SDKs
Official clients for server-to-server integrations (x-api-key — never in a browser): TypeScript (@seatschart/sdk, hand-written) and Python, Ruby, PHP, Java, .NET and Go, generated from openapi.json with a small hand-written runtime per language.
Every SDK ships the same three safety nets:
- Automatic retries of
429 Too Many Requestsand503 Service Unavailable: exponential backoff with full jitter (250 ms base, 8 s cap, 4 attempts by default, configurable), honouringRetry-After(seconds or HTTP date; a wait longer than 30 s is not attempted — the error is returned). - Only safe requests are retried:
GET,PUT,DELETE, or any request carrying anIdempotency-Key. The same key is resent, so the API replays the stored outcome instead of applying the operation twice. APOSTwithout a key is never retried. - Request timeouts: every attempt has a 30 s timeout, and the server SDKs also give up connecting after 10 s (as seats.io's SDKs). A timed-out attempt is retried under the same rule as a
503; after the last one the call fails with a typed timeout error (codetimeout). The outcome on the server is then unknown: retry the operation with the same idempotency key.
Use one idempotency key per logical operation (for example derived from your order id: order-4711:confirm) and reuse it for every retry of that operation; a new operation needs a new key.
Quick start
npm install @seatschart/sdk # TypeScript (Node / Bun)
pip install seatschart # Python
gem install seatschart # Ruby
composer require seatschart/seatschart-php # PHP
dotnet add package SeatsChart.Client # .NET
go get github.com/seatschart/seatschart-go # Go
# Java (Maven / Gradle): io.github.seatschart:seatschart-clientTypeScript (Node / Bun)
import { SeatsChart } from "@seatschart/sdk";
const sc = new SeatsChart({ apiBase: "https://api.seatschart.com", apiKey: process.env.SEATSCHART_KEY!,
retry: { maxAttempts: 5 } }); // retry: false disables retries
await sc.events.changeObjectStatuses({ statusChanges: [
{ eventKey: "show-2026-12-01", objects: ["A-1", "A-2"], status: "booked" },
{ eventKey: "show-2026-12-02", objects: ["A-1"], status: "booked" },
] }, { idempotencyKey: "order-4711:book" });Python
import seatschart
from seatschart.retry import RetryPolicy, install_retry, new_idempotency_key
config = seatschart.Configuration(host="https://api.seatschart.com")
client = install_retry(seatschart.ApiClient(config, header_name="x-api-key", header_value=KEY), RetryPolicy(max_attempts=5))
seatschart.ObjectStatusApi(client).post_api_events_actions_change_object_status(body, idempotency_key="order-4711:book")
# new_idempotency_key() returns a fresh key for a new operationRuby
require 'seatschart'
SeatsChart.configure { |c| c.host = 'api.seatschart.com'; c.api_key['x-api-key'] = ENV['SEATSCHART_KEY'] }
SeatsChart::Retry.policy = SeatsChart::Retry::Policy.new(max_attempts: 5) # optional
api = SeatsChart::ObjectStatusApi.new
api.post_api_events_actions_change_object_status(body, idempotency_key: 'order-4711:book')PHP
use SeatsChart\Client\Runtime\Retry;
$config = SeatsChart\Client\Configuration::getDefaultConfiguration()
->setHost('https://api.seatschart.com')->setApiKey('x-api-key', getenv('SEATSCHART_KEY'));
$api = new SeatsChart\Client\Api\ObjectStatusApi(Retry::client(new Retry(5)), $config);
$api->postApiEventsActionsChangeObjectStatus($body, 'order-4711:book'); // Retry::newIdempotencyKey() for a fresh keyJava
ApiClient api = Configuration.getDefaultApiClient().setBasePath("https://api.seatschart.com");
api.setApiKey(System.getenv("SEATSCHART_KEY"));
api.setHttpClient(api.getHttpClient().newBuilder()
.addInterceptor(new RetryInterceptor(RetryPolicy.defaults().withMaxAttempts(5))).build());
new ObjectStatusApi(api).postApiEventsActionsChangeObjectStatus(body, "order-4711:book"); // RetryPolicy.newIdempotencyKey().NET
using SeatsChart.Client.Runtime;
var http = RetryHandler.CreateHttpClient(new RetryPolicy { MaxAttempts = 5 }); // 10 s to connect, 30 s per attempt
var config = new Configuration { BasePath = "https://api.seatschart.com" };
config.ApiKey["x-api-key"] = Environment.GetEnvironmentVariable("SEATSCHART_KEY");
await new ObjectStatusApi(http, config).PostApiEventsActionsChangeObjectStatusAsync(body, "order-4711:book");
// Idempotency.NewKey() for a fresh key; with IHttpClientFactory: AddHttpMessageHandler(() => new RetryHandler()).Go
cfg := seatschart.NewConfiguration()
cfg.Servers = seatschart.ServerConfigurations{{URL: "https://api.seatschart.com"}}
cfg.HTTPClient = seatschart.NewRetryingHTTPClient(nil, seatschart.DefaultRetryPolicy())
cfg.AddDefaultHeader("x-api-key", os.Getenv("SEATSCHART_KEY"))
client := seatschart.NewAPIClient(cfg)
_, err := client.ObjectStatusAPI.PostApiEventsActionsChangeObjectStatus(ctx).
PostApiEventsActionsChangeObjectStatusRequest(body).IdempotencyKey("order-4711:book").Execute()
// seatschart.NewIdempotencyKey() for a fresh key.Generated method and class names follow the OpenAPI operations (one API class per tag: ObjectStatusApi, EventLogApi, ChartsApi, UsageApi, …). Every write method takes an optional, typed Idempotency-Key argument.
Timeouts
| SDK | Default | Change it | Timeout error |
|---|---|---|---|
| TypeScript | 30 s per attempt, until the response is read | timeoutMs on the client or on one call (0 or Infinity: none); a call also takes an AbortSignal (signal) | SeatsChartTimeoutError (isSeatsChartTimeout(error)) |
| Python | 10 s to connect, 30 s to read | RetryPolicy(connect_timeout=…, timeout=…) (None or 0: none); a call's own _request_timeout wins | RequestTimeoutError |
| Ruby | 10 s to connect, 30 s in total | SeatsChart::Retry::Policy.new(connect_timeout:, timeout:); a positive config.timeout wins | SeatsChart::Retry::TimeoutError (an ApiError) |
| PHP | connect_timeout 10 s, timeout 30 s | new Retry(…, $timeout, $connectTimeout), or Guzzle options passed to Retry::client() | TimeoutException (a Guzzle ConnectException) |
| Java | 10 s to connect, 30 s read and write timeout | RetryPolicy.defaults().withTimeouts(connect, perAttempt) (Duration.ZERO: none) | SeatsChartTimeoutException, the cause of the ApiException (RetryPolicy.isTimeout(e)) |
| .NET | 10 s to connect, 30 s per attempt, until the body is read | RetryHandler.CreateHttpClient(new RetryPolicy { Timeout = … }, connectTimeout: …) | SeatsChartTimeoutException (Timeouts.IsTimeout(e)) |
| Go | 10 s to connect, 30 s per attempt, until the body is read | RetryPolicy.Timeout, RetryPolicy.ConnectTimeout (0: none) | *TimeoutError (IsTimeout(err)) |
A retryOnTimeout / retry_on_timeout / RetryOnTimeout option set to false returns the first timeout instead of retrying it. Your own cancellation (an aborted signal, a cancelled context or token) is never turned into a timeout and is never retried.
