Skip to content

Quickstart

Go from zero to a shipped test order in about five minutes — catalog, artwork, product, order, simulated production and a signed webhook.

You will create a real product and a test order end to end, using test mode: nothing is printed, shipped or charged, and test credits are free. Every step shows the request in cURL, Node.js and Python and what to look for in the response.

You need: a Swaglists account, a terminal, and (for step 8) any URL that can receive HTTPS requests.

1. Get a test key

  1. In the dashboard, open Developers → API keys and click Create key.
  2. Choose Test mode and Full access, name it quickstart, and copy the secret. It starts with sk_test_ and is shown only once.
  3. Store it in an environment variable and call GET /account to check it works:
export API_KEY="sk_test_your_key_here"

curl https://swaglists.com/api/v1/account \
  -H "Authorization: Bearer $API_KEY"

You should see "object": "account" and "mode": "test". A 401 means the key was not sent or mistyped — see Authentication.

Note

The Node.js and Python tabs build one script step by step: keep appending each step's code to the same file.

2. Add test credits

Orders are paid from a prepaid wallet. Test mode has its own wallet; fill it with free test credits ($1,000 per call):

curl -X POST https://swaglists.com/api/v1/test/wallet/fund \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

available is in cents: 100000 = $1,000.

3. Pick a catalog product

List the products you can sell. Every variant carries your wholesale price in cents:

curl "https://swaglists.com/api/v1/catalog/products?limit=3" \
  -H "Authorization: Bearer $API_KEY"
Response (abridged)
{
  "object": "list",
  "data": [
    {
      "object": "catalog_product",
      "id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1",   // ← keep this
      "title": "Classic Unisex Tee",
      "price_from": 1299,
      "placements": [
        { "key": "front", "recommended_width_px": 4500, "recommended_height_px": 5400, "min_dpi": 150 }
      ],
      "variants": [
        { "id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "price": 1299, "available": true }
      ]
    }
  ],
  "has_more": true
}

Keep the product id and a placement key (usually front). Use catalog/products/{id} to see every variant, placement and mockup template — see Catalog & placements.

4. Upload artwork

Upload a PNG (transparent background recommended). No artwork handy? Download our sample — a 3000 × 3000 px PNG:

Download the sample artwork
curl -o artwork.png https://swaglists.com/docs/assets/sample-artwork.png
curl -X POST https://swaglists.com/api/v1/files \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@artwork.png" \
  -F "purpose=artwork"

Already host your artwork? Send JSON instead: {"url": "https://cdn.example.com/art.png"} — we download it once. Keep the file id.

5. Create a product

A product = catalog product + your designs + variants with SKUs. Omitting position centers the artwork and fits it inside the print area; "variants": "all" adds every available color and size:

curl -X POST https://swaglists.com/api/v1/products \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1",
    "title": "Quickstart Tee",
    "designs": [{ "placement": "front", "layers": [{ "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9" }] }],
    "variants": "all",
    "retail_price": 2900
  }'

In cURL, replace the two ids with yours. The response lists variants[], each with a generated sku (you can set your own — see Products & SKUs); use one whose available is true. It also has a warnings array (for example dpi_low if the artwork is small for the print area). Mockups render in the background.

6. Create a test order

Send the end customer's address and the SKU. Always send an Idempotency-Key and your own order id as external_id, so retries never create duplicates:

curl -X POST https://swaglists.com/api/v1/orders \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "external_id": "quickstart-1001",
    "shipping_method": "standard",
    "recipient": {
      "name": "Jane Doe",
      "address1": "123 Market St",
      "city": "San Francisco",
      "state_code": "CA",
      "postal_code": "94107",
      "country_code": "US",
      "email": "jane@example.com"
    },
    "items": [{ "sku": "YOUR-SKU", "quantity": 1 }]
  }'

The order comes back with "status": "processing" and "funds_status": "held": the total was reserved from your test wallet and the order is on its way to (simulated) production. The response also has a tracking_page_url — your branded tracking page for the customer.

Tip

Want the price first? POST /orders/estimate takes the same body and returns exactly what the order will cost, without creating it.

7. Watch it ship

Test orders progress on their own (in production after about 2 minutes, shipped after about 5, delivered after about 15). Skip the wait: each call to the advance endpoint moves the order one step — in_production → shipped (with tracking) → delivered:

curl -X POST https://swaglists.com/api/v1/test/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/advance \
  -H "Authorization: Bearer $API_KEY"

After the second call, shipments[0] has a carrier, tracking_number and tracking_url. Fetch the order any time with GET /orders/{id} — or by your own id: GET /orders/ext:quickstart-1001.

8. Receive a webhook

Webhooks tell your backend when orders change. Run a small receiver that verifies the signature (it uses the official Standard Webhooks library):

// webhook-server.mjs — npm install standardwebhooks
import http from "node:http";
import { Webhook } from "standardwebhooks";

const wh = new Webhook(process.env.WEBHOOK_SECRET); // "whsec_…"

http
  .createServer(async (req, res) => {
    const chunks = [];
    for await (const chunk of req) chunks.push(chunk);
    // the RAW body, decoded once all chunks are in (a character can span two chunks) — verify before parsing
    const body = Buffer.concat(chunks).toString("utf8");
    try {
      const event = wh.verify(body, req.headers);
      console.log(event.type, event.data.object.id, event.data.object.status ?? "");
      res.writeHead(204).end();
    } catch {
      res.writeHead(400).end("invalid signature");
    }
  })
  .listen(3000, () => console.log("Listening on :3000"));

Expose it on a public HTTPS URL (for example with a tunnel: ngrok http 3000 or cloudflared tunnel --url http://localhost:3000), then register the URL. The response contains the signing secret — only this once:

cURL
curl -X POST https://swaglists.com/api/v1/webhook_endpoints \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "url": "https://your-tunnel.example.com/", "enabled_events": ["*"] }'

Restart the receiver with WEBHOOK_SECRET set to that secret, then send a test event (use the endpoint id from the response):

cURL
curl -X POST https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2/test \
  -H "Authorization: Bearer $API_KEY"

Your receiver prints webhook_endpoint.test. Create another order and advance it: you will see order.created, order.processing, order.in_production, shipment.created, order.shipped and order.delivered.

You did it

You created a product, placed an order paid with credits, watched it ship and received signed webhooks. Next: