# curl quickstart

Source: https://portal.printedsimply.com/docs/quickstarts/curl

Quickstart · Any language

One shell, five commands, a $0 sandbox order on its way.

About 4 minutes $0 sandbox key Ends with a sandbox order on its way

## Step 1: Create a sandbox key

In the dashboard, open API keys and create a key in Test mode. It starts with ps_test_ — test keys are free, never charge a card, and never reach a print facility. You can create one before adding a payment method.

[Create a test key](https://portal.printedsimply.com/dashboard/api-keys?env=test)

shell:

```bash
export PRINTEDSIMPLY_API_KEY=ps_test_YOUR_KEY
```

A live key (ps_live_) takes the same requests. A real order also needs a card on file and your own artwork: Going live, at the end of this page, has the four changes.

## Step 2: Pick a SKU

Every response is the same envelope: status, data, and request_id. Quote the request_id in any support thread and we can find the exact call. Each product's sku is what an order names.

shell:

```bash
curl -s "https://portal.printedsimply.com/api/v1/products?limit=3" \
  -H "x-api-key: $PRINTEDSIMPLY_API_KEY"
```

data.products:

```json
[
  {
    "sku": "sticker-die-cut-3x3",
    "name": "Die-Cut Sticker, 3×3 in",
    "category": "stickers"
  },
  {
    "sku": "wall-decal-24x36",
    "name": "Wall Decal, 24×36 in",
    "category": "decals"
  },
  {
    "sku": "magnet-3x3",
    "name": "Magnet, 3×3 in",
    "category": "magnets"
  }
]
```

Rows carry more than these three fields, the price of one unit among them; POST /v1/orders/quote prices a whole order. The order below names the first row's sticker as sticker-die-cut-3x3: a SKU is matched whatever its case.

## Step 3: Place the order

The order's reference doubles as its Idempotency-Key: replaying the same key with the same payload returns the original order instead of creating a second one; replaying it with a different payload is rejected with 422 rather than silently charging twice. A new order needs a new reference as well as a new key: one reference is one order for 30 days, so the same reference under another key is refused with 409 duplicate_reference, naming the order that has it.

shell:

```bash
curl -X POST https://portal.printedsimply.com/api/v1/order \
  -H "x-api-key: $PRINTEDSIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-$(date +%s)" \
  -d '{
    "items": [
      { "sku": "sticker-die-cut-3x3", "quantity": 100,
        "artwork_url": "https://printedsimply.com/samples/sticker-3x3.png" }
    ],
    "address_to": {
      "name": "Jane Doe", "address1": "123 Main St",
      "city": "Austin", "state": "TX", "zip": "78701", "country": "US"
    },
    "shipping": { "method": "standard" }
  }'
```

response:

```json
{
  "status": "success",
  "data": {
    "order_id": "test_ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
    "portal_order_id": "ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
    "tracking_url": "https://printedsimply.com/track/eyJ2IjoxLCJ0IjoidHJhY2tpbmciLCJ0b2siOiJ0cmtfQXF1SkZxRExEa2lzSzZKaC1IQUJIejlMIn0.199c0c58721512fcccd784902c422ca4e827c6d09b7e495bbb4db9b06ae62003",
    "test_mode": true,
    "lifecycle": "simulated",
    "charged": "$0.00",
    "artwork_check": {
      "lines": [
        {
          "item_index": 0,
          "sku": "sticker-die-cut-3x3",
          "status": "passed",
          "width_px": 1200,
          "height_px": 1200,
          "print_size_in": [
            3,
            3
          ],
          "effective_dpi": 400,
          "min_dpi": 300,
          "findings": []
        }
      ],
      "would_refuse": false
    }
  },
  "request_id": "4e3753e1-48dd-4313-bfd8-48e4af4e116a"
}
```

## Step 4: Skip the wait

Move the sandbox order straight to shipped instead of waiting for the schedule. Put the order_id from the response in ORDER_ID first.

shell:

```bash
ORDER_ID=test_ord_YOUR_ORDER_ID   # data.order_id from the response

curl -X POST "https://portal.printedsimply.com/api/v1/order/$ORDER_ID/simulate" \
  -H "x-api-key: $PRINTEDSIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_state": "shipped"}'
```

response:

```json
{
  "status": "success",
  "data": {
    "order_id": "test_ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
    "portal_order_id": "ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
    "status": "shipped",
    "simulated": true
  },
  "request_id": "4e3753e1-48dd-4313-bfd8-48e4af4e116a"
}
```

Left alone, a sandbox order moves on by itself: a scheduled job takes it to in_production, shipped and delivered over about five minutes, firing the same signed webhooks at each step. simulate does not wait for that schedule. It takes in_production, shipped, delivered, cancelled or issue_flagged, and only on a test key. An order the schedule has already delivered answers 400 already_terminal; to rehearse the step again, place a new order with a new reference and Idempotency-Key (the sample uses one value for both; the same key replays the delivered order, and the same reference under a new key is refused 409 duplicate_reference).

## Step 5: Open the tracking link and watch it deliver

The create response carries tracking_url. Open it in a browser, then read the order: once it has shipped, tracking carries the sandbox tracking number (TRK-TEST-…) and its carrier. Simulate delivered, or wait, to watch it deliver.

shell:

```bash
curl -s "https://portal.printedsimply.com/api/v1/order/$ORDER_ID" \
  -H "x-api-key: $PRINTEDSIMPLY_API_KEY"
```

Sandbox orders run the real lifecycle on a compressed clock: created → in_production → shipped → delivered, firing genuinely HMAC-signed webhooks at every transition through the same delivery pipeline live orders use. Leave the tracking page open.

## Going live

The sandbox order above never charges, prints or ships. A real one takes four changes.

### Add a card in Billing

A live order is charged to the card on file when it is placed. Without one, POST /v1/order answers 402 no_payment_method and nothing is placed.

[Open Billing](https://portal.printedsimply.com/dashboard/billing)

### Create a live key

On the API keys page, create a key in Live mode. It starts with ps_live_ and is shown in full once, so store it where your server reads secrets, never in a browser.

[Create a live key](https://portal.printedsimply.com/dashboard/api-keys?env=live)

### Send the same request with your own artwork

Swap in the live key, your customer's address and your artwork: an https link to the file (PNG, PDF or SVG), or the id POST /v1/assets returns, as print_file. A live order's artwork is checked before anything is charged: a line with no artwork answers 422 artwork_required, and a file that cannot be printed answers 422 artwork_not_printable.

### Subscribe a live-mode webhook

A subscription in test mode receives sandbox events only. For real orders, subscribe your endpoint in live mode (or all) on the Webhooks page or with POST /v1/webhooks, and verify X-PS-Signature-V2 on every delivery.

[Open Webhooks](https://portal.printedsimply.com/dashboard/webhooks)

## Scopes this page needs

A key created without an explicit scope list gets all of them. If you scope the key down, grant at least these:

- `products:read`
- `orders:write`
- `orders:read`

## Order placed. What's next?

- [Subscribe to webhooks](https://portal.printedsimply.com/docs/webhooks)

  Get order.shipped pushed to you instead of polling — signed, replayable, deduped.

- [Understand the limits](https://portal.printedsimply.com/docs/rate-limits)

  Per-plan rate and daily limits, the headers we return, and how to back off honestly.

- [Browse the API reference](https://portal.printedsimply.com/docs/api-reference)

  Every v1 endpoint, with its required scopes and response shape.

- [Try another quickstart](https://portal.printedsimply.com/docs/quickstarts)

  The same order in curl, TypeScript, Python or PHP, or from your framework.
