Cosmoner Docs
SDKs

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.

LanguagePackageRequires
JavaScript / TypeScript@cosmoner/sdkNode.js 18+
Pythoncosmoner-sdkPython 3.9+
PHPcosmoner/sdkPHP 8.1+

The source is on GitHub at datablock-dev/cosmoner-sdk, under the MIT licence.

Install

npm install @cosmoner/sdk

Create 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

OptionDefaultDescription
apiKey / api_key—Required. Your API key.
projectId / project_id—The project every call works in unless it names another.
baseUrl / base_urlhttps://api.cosmoner.comOverride the API's address.
timeout30 secondsPer-request timeout. Milliseconds in JavaScript (30000), seconds in Python and PHP (30.0).
maxRetries / max_retries2Retries for transient failures. 0 turns retries off.
httpClientCurlHttpClientPHP 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;
  }
}
ErrorRaised on
ValidationError400, 422 — details holds the field-level issues
AuthenticationError401 — the key is missing, revoked or expired
InsufficientScopeError403 — the key lacks a scope, named in the message
NotFoundError404
ConflictError409
RateLimitError429 — retryAfter / retry_after is in seconds, when the API sends it
ServerError5xx
CosmonerTimeoutErrorThe request exceeded timeout
CosmonerConnectionErrorDNS, 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

NamespaceWhat it doesPage
emailSend transactional email through an SMTP credentialEmail
appsDeploy image apps and wait for the rolloutApps
webhooksManage endpoints, inspect deliveries, verify signaturesWebhooks
secrets, variablesManage the values a deployment file refers toSecrets and Variables
hostingRead web hosting sites and their SFTP accessHosting
—Validate .cosmoner/deployment.yaml offlineDeployment 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.

On this page