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 Requests and 503 Service Unavailable: exponential backoff with full jitter (250 ms base, 8 s cap, 4 attempts by default, configurable), honouring Retry-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 an Idempotency-Key. The same key is resent, so the API replays the stored outcome instead of applying the operation twice. A POST without 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 (code timeout). 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

bash
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-client

TypeScript (Node / Bun)

ts
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

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 operation

Ruby

ruby
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

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 key

Java

java
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

csharp
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

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

SDKDefaultChange itTimeout error
TypeScript30 s per attempt, until the response is readtimeoutMs on the client or on one call (0 or Infinity: none); a call also takes an AbortSignal (signal)SeatsChartTimeoutError (isSeatsChartTimeout(error))
Python10 s to connect, 30 s to readRetryPolicy(connect_timeout=…, timeout=…) (None or 0: none); a call's own _request_timeout winsRequestTimeoutError
Ruby10 s to connect, 30 s in totalSeatsChart::Retry::Policy.new(connect_timeout:, timeout:); a positive config.timeout winsSeatsChart::Retry::TimeoutError (an ApiError)
PHPconnect_timeout 10 s, timeout 30 snew Retry(…, $timeout, $connectTimeout), or Guzzle options passed to Retry::client()TimeoutException (a Guzzle ConnectException)
Java10 s to connect, 30 s read and write timeoutRetryPolicy.defaults().withTimeouts(connect, perAttempt) (Duration.ZERO: none)SeatsChartTimeoutException, the cause of the ApiException (RetryPolicy.isTimeout(e))
.NET10 s to connect, 30 s per attempt, until the body is readRetryHandler.CreateHttpClient(new RetryPolicy { Timeout = … }, connectTimeout: …)SeatsChartTimeoutException (Timeouts.IsTimeout(e))
Go10 s to connect, 30 s per attempt, until the body is readRetryPolicy.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.