<!-- Source: https://useworkloom.com/dev/sandbox/ · Workloom API v1 -->

# Developer sandbox

A separate workspace of made-up companies, people and deals, for building and testing an integration. What you write there is saved there, and nothing is ever sent, called or charged. Webhooks still reach your server.

- **Make the sandbox**: In Workloom, open Settings › API and webhooks and choose Make a sandbox. It comes with Starter and above, one per workspace.
- **Open it and make a key**: Choose Open sandbox. In the sandbox, open its own Settings › API and webhooks and make a key. Sandbox keys start `wl_sbx_`.
- **Call the sandbox**: Send that key to `https://sandbox-api.useworkloom.com/api/public/v1`. Every endpoint works as it does on the live API.

**Check your sandbox key**

```bash
curl https://sandbox-api.useworkloom.com/api/public/v1/ \
  -H "Authorization: Bearer $WORKLOOM_SANDBOX_KEY"
```

```javascript
const res = await fetch("https://sandbox-api.useworkloom.com/api/public/v1/", {
  headers: { Authorization: `Bearer ${process.env.WORKLOOM_SANDBOX_KEY}` },
});
console.log(await res.json());
```

```python
import os, requests

res = requests.get(
    "https://sandbox-api.useworkloom.com/api/public/v1/",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_SANDBOX_KEY']}"},
)
print(res.json())
```

## What is in it

It starts with 40 made-up companies, 120 contacts at them, 28 deals across every stage, a list, a live weave and an active sequence, so every endpoint has something to read and both enrol endpoints have somewhere to put people. Every address ends in `.example` and every phone number is in a reserved fictional range.

## How it differs from the live API

|   | Live API | Sandbox |
| --- | --- | --- |
| Base URL | `https://api.useworkloom.com/api/public/v1` | `https://sandbox-api.useworkloom.com/api/public/v1` |
| Keys | `wl_live_`, `wl_test_` | `wl_sbx_`, made inside the sandbox |
| Records | Your workspace | Made-up records, yours to change |
| Writes | Saved | Saved, in the sandbox only |
| Email, calls, LinkedIn | Sent | Never sent: kept inside the sandbox |
| Credits | Spent | Never charged |
| Webhooks | Delivered | Delivered, signed and retried the same way |
| Rate limit | 300 a minute per key | 300 a minute per key |

> A `wl_sbx_` key sent to the live API gets `401` with code `sandbox_key`, and a live key sent to the sandbox gets `invalid_key`. Neither reaches the other’s records.

## Make events happen

Nobody replies, books a meeting or calls in a sandbox. `POST /sandbox/events` makes one of those things happen to one of its contacts, and every webhook endpoint subscribed to that event gets the delivery. Events the API can cause itself are made the real way: create a contact for `contact.created`, move a deal for `deal.won`.

**A reply arrives**

```bash
curl https://sandbox-api.useworkloom.com/api/public/v1/sandbox/events \
  -H "Authorization: Bearer $WORKLOOM_SANDBOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "reply.received", "contact_id": "<a sandbox contact id>", "category": "meeting"}'
```

It takes `reply.received`, `email.opened`, `email.clicked`, `email.bounced`, the five `meeting.*` events, `booking.made`, `form.submitted`, `call.logged`, `call.missed`, `tell.fired` and `contact.unsubscribed`. The live API answers this endpoint with `404` and code `sandbox_only`.

## Reset and removal

- Reset to starting records puts the sandbox back as it began. Everything made in it goes, its keys and webhook endpoints included.
- A sandbox nobody has opened or called for 90 days is removed. Make a new one when you need it.
- Making, resetting and deleting a sandbox need the API keys permission and a two-step verification code, as making a key does.
