SDK Overview
Install the official JavaScript, Python and PHP SDKs, configure a client, and handle retries and errors.
The SDKs wrap the Cosmoner API in a Cosmoner client with one namespace per
service. All three are written by hand and kept in step: the same namespaces,
the same methods, the same retry rules and the same error types, so code moves
between languages without surprises.
| Language | Package | Requires |
|---|---|---|
| JavaScript / TypeScript | @cosmoner/sdk | Node.js 18+ |
| Python | cosmoner-sdk | Python 3.9+ |
| PHP | cosmoner/sdk | PHP 8.1+ |
The source is on GitHub at datablock-dev/cosmoner-sdk, under the MIT licence.
Install
npm install @cosmoner/sdkCreate a client
You need an API key and the id of the project it belongs to. Give the key only the scopes your code uses — each page in this section names the scopes its methods need.
import { Cosmoner } from "@cosmoner/sdk";
const client = new Cosmoner({
apiKey: process.env.COSMONER_API_KEY!,
projectId: process.env.COSMONER_PROJECT_ID,
});Read the key from the environment or a secret store rather than writing it into source. Anyone holding it can act on the project within its scopes.
Configuration
| Option | Default | Description |
|---|---|---|
apiKey / api_key | — | Required. Your API key. |
projectId / project_id | — | The project every call works in unless it names another. |
baseUrl / base_url | https://api.cosmoner.com | Override the API's address. |
timeout | 30 seconds | Per-request timeout. Milliseconds in JavaScript (30000), seconds in Python and PHP (30.0). |
maxRetries / max_retries | 2 | Retries for transient failures. 0 turns retries off. |
httpClient | CurlHttpClient | PHP only. See Custom HTTP client in PHP. |
Working across projects
projectId is optional on the client, so one client can span projects. Every
method also accepts it per call, and the per-call value wins:
const client = new Cosmoner({ apiKey: process.env.COSMONER_API_KEY! });
await client.apps.list({ projectId: "proj_staging" });A key is still bound to the project it was created in. Naming a different project only works with a key from that project — see What a Key Can Reach.
Responses
Methods return the API's response envelope unchanged, so the result of a call
is in data:
const { data: apps } = await client.apps.list();The JavaScript SDK ships TypeScript types for every response. Python returns
plain dicts and PHP returns arrays with documented shapes, so field names are
the API's own camelCase in every language — result["data"]["messageId"], not
message_id.
Retries
Transient failures are retried automatically, with exponential backoff and
jitter. When the API sends Retry-After, the SDK waits at least that long.
- 429 is always retried. The API refused the request before processing it, so sending it again cannot repeat a side effect.
- Timeouts and 5xx responses are retried for reads only. A write such as sending an email is not replayed, because the API may have finished the work before failing to answer. Retrying could send the email twice.
Set maxRetries to 0 to handle every failure yourself.
Errors
Every failure raises a subclass of CosmonerError, so you can catch broadly or
pick out the cases you handle differently:
import { CosmonerError, RateLimitError } from "@cosmoner/sdk";
try {
await client.apps.deploy(appId, { tag: "v2" });
} catch (err) {
if (err instanceof RateLimitError) {
console.error(`Retry in ${err.retryAfter}s`);
} else if (err instanceof CosmonerError) {
console.error(err.status, err.code, err.message);
console.error(err.docsUrl); // set when the docs explain the fix
} else {
throw err;
}
}| Error | Raised on |
|---|---|
ValidationError | 400, 422 — details holds the field-level issues |
AuthenticationError | 401 — the key is missing, revoked or expired |
InsufficientScopeError | 403 — the key lacks a scope, named in the message |
NotFoundError | 404 |
ConflictError | 409 |
RateLimitError | 429 — retryAfter / retry_after is in seconds, when the API sends it |
ServerError | 5xx |
CosmonerTimeoutError | The request exceeded timeout |
CosmonerConnectionError | DNS, TCP, TLS or socket failure |
code (errorCode in PHP) is the API's error code, such as
INSUFFICIENT_SCOPE. Branch on it rather than on the message — codes are
stable, wording is not. The Getting Started guide explains each
code and how to fix it.
Arguments are checked before any request is sent. A missing required argument
fails at once, with no network call: an Error in JavaScript, a ValueError
in Python and an InvalidArgumentException in PHP.
Async Python
AsyncCosmoner mirrors the sync client method for method, with await:
from cosmoner import AsyncCosmoner
async with AsyncCosmoner(api_key=api_key, project_id=project_id) as client:
apps = await client.apps.list()Both Python clients hold a connection pool. Use them as context managers, or
call client.close() / await client.aclose() when you are done.
Custom HTTP client in PHP
Requests go through the HttpClient interface, backed by ext-curl by default.
Supply your own to use a PSR-18 client, add logging, or stub HTTP in tests:
use Cosmoner\Sdk\Cosmoner;
use Cosmoner\Sdk\HttpClient;
use Cosmoner\Sdk\HttpResponse;
final class LoggingHttpClient implements HttpClient
{
public function send(string $method, string $url, array $headers, ?string $body, float $timeout): HttpResponse
{
// ...
}
}
$client = new Cosmoner(apiKey: getenv('COSMONER_API_KEY'), httpClient: new LoggingHttpClient());What the SDKs cover
| Namespace | What it does | Page |
|---|---|---|
email | Send transactional email through an SMTP credential | |
apps | Deploy image apps and wait for the rollout | Apps |
webhooks | Manage endpoints, inspect deliveries, verify signatures | Webhooks |
secrets, variables | Manage the values a deployment file refers to | Secrets and Variables |
hosting | Read web hosting sites and their SFTP access | Hosting |
| — | Validate .cosmoner/deployment.yaml offline | Deployment Files |
The SDKs grow with the API. For an endpoint they do not wrap yet, call it directly — it is plain HTTP with a bearer token, documented in the API reference.