Skip to content
Review environment of the Cloudprinter Parallel build — fictional data, not the production Cloudprinter service.

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.