> ## Documentation Index
> Fetch the complete documentation index at: https://www.zinc.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Sandbox Quickstart

> Go from nothing to a delivered sandbox order in about two minutes — no account, no signup, no configuration.

No account needed. Four steps, about two minutes.

<Tip>
  Pointing an agent at this instead of reading it yourself? The same walkthrough is served as plain markdown at [`GET /sandbox/quickstart`](https://api.zinc.com/sandbox/quickstart), written to be executed rather than read.
</Tip>

<Steps>
  <Step title="Mint a sandbox key" stepNumber={1}>
    ```bash theme={null}
    curl -X POST https://api.zinc.com/sandbox/keys
    ```

    No authentication. An empty body works; both fields are optional:

    ```bash theme={null}
    curl -X POST https://api.zinc.com/sandbox/keys \
      -H "Content-Type: application/json" \
      -d '{
        "name": "acme-shopping-agent dev testing",
        "email": "operator@example.com"
      }'
    ```

    * `name` becomes the key's label, so a human claiming it later can tell what it was for.
    * `email` is who should be told about claiming this sandbox. Never required, never used for anything else.

    The response is self-guiding:

    ```json theme={null}
    {
      "api_key": "zn_test_...",
      "expires_policy": "This key expires after 7 days without use. Everything it creates is sandbox data and is deleted with it.",
      "quickstart_url": "https://api.zinc.com/sandbox/quickstart",
      "example_order": {
        "products": [ ... ],
        "shipping_address": { ... },
        "max_price": 2500
      },
      "claim_url": "https://app.zinc.com/claim/...",
      "next": [
        "POST /orders with this key ...",
        "..."
      ]
    }
    ```

    <Warning>
      Save the `claim_url`. It's returned **once** — only its hash is stored, so it can't be regenerated. Losing it means minting a new sandbox.
    </Warning>
  </Step>

  <Step title="Place a sandbox order" stepNumber={2}>
    Send the key as a Bearer token. Test keys route to the sandbox automatically — no extra headers, no mode flag:

    ```bash theme={null}
    export ZINC_KEY=zn_test_...

    curl -X POST https://api.zinc.com/orders \
      -H "Authorization: Bearer $ZINC_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "products": [
          {"url": "https://zinc.com/shop/products/test-success", "quantity": 1}
        ],
        "shipping_address": {
          "first_name": "Sandbox", "last_name": "Agent",
          "address_line1": "101 Market St", "city": "San Francisco",
          "state": "CA", "postal_code": "94105",
          "phone_number": "4155552671", "country": "US"
        },
        "max_price": 2500
      }'
    ```

    That body is exactly what the mint response hands back as `example_order` — it can be sent unchanged.

    <Info>
      `max_price` is in **cents** and is required on every order. It's the ceiling you authorize for the total, including tax and shipping. Leave `idempotency_key` out unless you're generating a fresh UUID for it; one is generated for you when omitted.
    </Info>
  </Step>

  <Step title="Watch it happen" stepNumber={3}>
    ```bash theme={null}
    curl https://api.zinc.com/orders/<order_id> \
      -H "Authorization: Bearer $ZINC_KEY"
    ```

    Sandbox orders run the real lifecycle on a compressed clock:

    | When            | What changes                                                                                                          |
    | --------------- | --------------------------------------------------------------------------------------------------------------------- |
    | \~30–120s       | `status` becomes `order_placed` — that **is** the terminal status of a successful order (`order_failed` if it didn't) |
    | \~1–3 min later | A tracking number attaches, and `tracking_numbers[].status` advances through `shipped` to `delivered`                 |

    Prefer not to poll? Register a webhook URL — test mode has its own webhook config, separate from live:

    ```bash theme={null}
    curl -X POST https://api.zinc.com/users \
      -H "Authorization: Bearer $ZINC_KEY" \
      -H "Content-Type: application/json" \
      -d '{"webhook_url": "https://your-server.example/webhooks/zinc"}'
    ```
  </Step>

  <Step title="Rehearse the failure modes" stepNumber={4}>
    Swap the product slug to reproduce each error shape. This is the part worth spending time on — a happy-path integration meets its first real failure in production.

    Some fail **at creation**, some fail **after acceptance**:

    | Product slug                | Fails                                    |
    | --------------------------- | ---------------------------------------- |
    | `test-success`              | Nothing — places, ships, delivers        |
    | `test-invalid-address`      | At creation                              |
    | `test-url-unreachable`      | At creation                              |
    | `test-insufficient-funds`   | At creation                              |
    | `test-price-exceeded`       | After placement — watch the order status |
    | `test-out-of-stock`         | After placement                          |
    | `test-invalid-variant`      | After placement                          |
    | `test-shipping-unavailable` | After placement                          |

    All slugs live under `https://zinc.com/shop/products/`. Any other product URL — including a real Amazon one — simply succeeds in the sandbox. See [Sandbox & Testing](/docs/v2/api-reference/introduction/sandbox#test-products) for the error payloads each one produces.
  </Step>
</Steps>

## Practical notes

* **Persist the key.** It's good for 7 days of inactivity and any use resets the clock. An agent that stores its key needs the mint endpoint roughly once.
* **Don't loop on `429`.** The mint endpoint is capped per IP per day. A `429` means *reuse the key you already have*, not retry — wait out `Retry-After` if you genuinely need a new one.
* **`503` is retryable.** The mint path fails closed when the sandbox or its rate limiter is unavailable, rather than running uncapped. Back off and try again.
* **Sandbox validations are looser than live.** Balance checks, URL reachability, and address verification are all bypassed. See [Skipped Validations](/docs/v2/api-reference/introduction/sandbox#skipped-validations) before your first real order.

## Next step

<Card title="Going Live" icon="flag-checkered" href="/docs/v2/agent-sandbox/going-live">
  Claim the sandbox into a real account and swap in a live key.
</Card>
