SDK examples
Two generated SDKs for the native API (TypeScript first, Python second) are produced deterministically from GET /v1/openapi.json; their version tracks the API version (X-API-Version, currently 1.1.0). Existing CloudCore integrations keep their official SDK and change one URL, or use the compatible client below. Package names are provisional; the SDKs ship in the platform repository under sdks/ and are not published to a registry yet.
Existing CloudCore integrations: only the base URL changes
// Official CloudCore Node SDK (github.com/cloudprintercom/cloudcore-nodejs-sdk).
// The SDK hard-codes https://api.cloudprinter.com/cloudcore/1.0/ in its constructor;
// baseUrl is a public client property, so the ONLY change is one line:
const client = new Client(process.env.CLOUDCORE_APIKEY);
client.baseUrl = 'https://<this-platform-host>/cloudcore/1.0/'; // <- the only change
const quote = await client.order.quote({
country: 'DE',
items: [{ reference: 'line-1', product: 'poster_a2_matte', count: 1 }],
});
const order = await client.order.create({
reference: 'my-order-1001',
email: '[email protected]',
addresses: [{ type: 'delivery', firstname: 'Anna', lastname: 'Becker', street1: 'Hauptstrasse 1', zip: '10115', city: 'Berlin', country: 'DE' }],
items: [{ reference: 'line-1', product: 'poster_a2_matte', count: 1, files: [{ type: 'poster', url: 'https://files.example.com/poster.pdf' }] }],
});The SDK sends the apikey in the JSON body and calls orders, orders/add, orders/quote, orders/quote/info and products — all served by this platform at the same paths (with and without the trailing slash).
CloudCore-compatible TypeScript client
// CloudCore-compatible TypeScript client (sdks/cloudcore-compat-ts): the exact request shapes of the
// official Node SDK, zero dependencies, and a REQUIRED baseUrl (it never defaults to the legacy host).
import { CloudCoreClient, CloudCoreError } from '@cpp/cloudcore-compat-sdk';
const client = new CloudCoreClient({
apikey: process.env.CLOUDCORE_APIKEY, // sent in the JSON body as `apikey`
baseUrl: 'https://<this-platform-host>/cloudcore/1.0/', // the only thing a migrating integration changes
});
const quote = await client.order.quote({ country: 'DE', items: [{ reference: 'line-1', product: 'poster_a2_matte', count: 1 }] });
const created = await client.order.create({ reference: 'my-order-1001', email: '[email protected]', addresses: [/* … */], items: [/* … */] });
const info = await client.order.getInfo('my-order-1001'); // orders/info {apikey, reference}
const list = await client.order.getList(); // orders {apikey} (orders/ with pathStyle: 'docs')
try {
await client.order.getInfo('does-not-exist');
} catch (e) {
if (e instanceof CloudCoreError) console.error(e.status, e.code, e.body); // 404 validation:order_unknown {error, message}
}Same request shapes as the official SDK (orders/add with apikey appended, orders with {apikey},cancel/info/log with {apikey, reference}); errors carry the legacy {error, message} envelope. Parity with the legacy production API is verified only against documentation-derived fixtures so far.
Native API v1
TypeScript SDK
// Native API v1 — TypeScript SDK (sdks/native-ts), generated from GET /v1/openapi.json. Zero dependencies (fetch).
import { CloudprinterClient, ProblemError, idempotencyKeyFrom } from '@cpp/native-sdk';
const client = new CloudprinterClient({ baseUrl: 'https://<this-platform-host>', apiKey: process.env.CLOUDPRINTER_KEY });
// The key decides sandbox vs live (cpk_sandbox_… / cpk_live_…); the URL is the same.
// 1. Quote: order-able shipping options with a `quote` token (valid 48 h)
const quote = await client.createQuote({ country: 'US', state: 'NY', items: [{ reference: 'line-1', product: 'flyer_a5', count: 50 }] });
const option = quote.shipments[0].options[0];
// 2. Order: Idempotency-Key is REQUIRED. Derive it from your own order number so a retry replays instead of re-ordering.
const order = await client.createOrder({
quote: option.quote, email: '[email protected]',
addresses: [{ type: 'delivery', firstname: 'Gina', lastname: 'Tester', street1: '1 Main Street', zip: '10001', city: 'New York', state: 'NY', country: 'US' }],
items: [{ reference: 'line-1', product: 'flyer_a5', count: 50, files: [{ type: 'artwork', url: 'https://files.example.com/flyer.pdf' }] }],
}, { idempotencyKey: idempotencyKeyFrom('shop', 1001) });
// 3. Per-item cancel (idempotent: changed=false on a repeat; 'requested' while the print partner must confirm)
const cancel = await client.cancelOrderItem(order.id, order.items[0].id, { cause: 'customer changed mind' });
// 4. Pagination helper: every order across all pages
for await (const o of client.listOrdersAll({ limit: 100 })) console.log(o.reference, o.status, o.total.amount, o.total.currency);
// 5. Errors are RFC 7807 problem details
try { await client.getOrder('ord_does_not_exist'); }
catch (e) { if (e instanceof ProblemError) console.error(e.status, e.code, e.detail, e.correlationId); else throw e; }Typed requests and responses, RFC 7807 ProblemError, Idempotency-Key helpers, listOrdersAll pagination and anX-API-Version major check (ApiVersionMismatchError). Build: npx tsc -p sdks/native-ts/tsconfig.json.
Python SDK
# Native API v1 — Python SDK (sdks/native-python), generated from GET /v1/openapi.json. Standard library only.
from cloudprinter_native import CloudprinterClient, ProblemError, idempotency_key_from
client = CloudprinterClient("https://<this-platform-host>", api_key=os.environ["CLOUDPRINTER_KEY"])
quote = client.create_quote({"country": "US", "state": "NY", "items": [{"reference": "line-1", "product": "flyer_a5", "count": 50}]})
option = quote["shipments"][0]["options"][0]
order = client.create_order({
"quote": option["quote"], "email": "[email protected]",
"addresses": [{"type": "delivery", "firstname": "Gina", "lastname": "Tester", "street1": "1 Main Street", "zip": "10001", "city": "New York", "state": "NY", "country": "US"}],
"items": [{"reference": "line-1", "product": "flyer_a5", "count": 50, "files": [{"type": "artwork", "url": "https://files.example.com/flyer.pdf"}]}],
}, idempotency_key=idempotency_key_from("shop", 1001))
result = client.cancel_order_item(order["id"], order["items"][0]["id"], {"cause": "customer changed mind"})
for o in client.list_orders_all(limit=100):
print(o["reference"], o["status"], o["total"]["amount"], o["total"]["currency"])
try:
client.get_order("ord_does_not_exist")
except ProblemError as e:
print(e.status, e.code, e.detail, e.correlation_id) # 404 not_found:order …Standard library only (Python ≥ 3.11). Install from the repository: pip install ./sdks/native-python.
Plain fetch
// Native API v1 with plain fetch (Node 18+), no SDK. Keep the key server-side.
const BASE = 'https://<this-platform-host>';
const headers = { authorization: `Bearer ${process.env.CLOUDPRINTER_KEY}`, 'content-type': 'application/json' };
// 1. Quote
const quote = await (await fetch(`${BASE}/v1/quotes`, { method: 'POST', headers,
body: JSON.stringify({ country: 'US', state: 'NY', items: [{ reference: 'line-1', product: 'flyer_a5', count: 50 }] }) })).json();
const option = quote.shipments[0].options[0];
// 2. Order — the Idempotency-Key makes retries safe (same key + same body => same order)
const res = await fetch(`${BASE}/v1/orders`, { method: 'POST',
headers: { ...headers, 'idempotency-key': 'shop-order-1001' },
body: JSON.stringify({ quote: option.quote, email: '[email protected]',
addresses: [{ type: 'delivery', firstname: 'Gina', lastname: 'Tester', street1: '1 Main Street', zip: '10001', city: 'New York', state: 'NY', country: 'US' }],
items: [{ reference: 'line-1', product: 'flyer_a5', count: 50, files: [{ type: 'artwork', url: 'https://files.example.com/flyer.pdf' }] }] }) });
if (res.status === 409) throw new Error('Idempotency-Key reused with a different body');
const order = await res.json(); // 201 created, 200 replay of the same request
// 3. List with cursor pagination
let cursor = null;
do {
const page = await (await fetch(`${BASE}/v1/orders?limit=100${cursor ? `&cursor=${cursor}` : ''}`, { headers })).json();
for (const o of page.data) console.log(o.reference, o.status, o.total.amount, o.total.currency);
cursor = page.next_cursor;
} while (cursor);curl
curl -s https://<this-platform-host>/v1/orders \ -H "Authorization: Bearer $CLOUDPRINTER_KEY" \ -H "Idempotency-Key: shop-order-1001" \ -H "Content-Type: application/json" \ -d @order.json
Money fields are objects like { "amount_minor": "4250", "amount": "42.50", "currency": "USD" }. Use amount_minor for arithmetic; never parse amounts as floats.