# Coinbase sandbox: Exchange vs Advanced Trade vs Checkouts

URL: https://fincodelabs.com/en/blog/coinbase-sandbox · Publisher: Fincode (Fincode Yazılım ve Teknoloji A.Ş.), Istanbul, Turkey · Category: Exchange APIs · Published: 2026-11-06 · Updated: 2026-11-06

Coinbase sandbox explained: the Exchange sandbox login, keys and fake funds, the mocked Advanced Trade sandbox, Checkouts, and what each one can prove.

**Short answer:** For trading code, the **Coinbase sandbox** means two different test environments, so test in the one that matches the API you will call in production. The Coinbase Exchange sandbox (`api-public.sandbox.exchange.coinbase.com`) has its own login, API keys, unlimited fake funds and order books; the Advanced Trade sandbox (`api-sandbox.coinbase.com`) needs no key and returns fixed, mocked responses. Neither shows production prices or fills: on 5 November 2026 the Exchange sandbox had 9 online markets against 516 in production.

This guide rests on Coinbase's developer documentation, read on 5 November 2026, and on requests sent that day from Python 3.11 with no account and no real keys; private endpoints were called only to record their errors.

It is a technical guide, not a recommendation of any platform or strategy. Automated trading can lose money, and which products you may use depends on your jurisdiction and Coinbase's terms. For readers in Turkey: Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized.

## Which Coinbase sandbox do you need?

Choose by the production API: Exchange code belongs in the Exchange sandbox, Advanced Trade code can only be checked against canned responses, and payment checkouts have their own sandbox.

**Coinbase test environments, from Coinbase's documentation and requests on 5 November 2026**

| Item | Exchange sandbox | Advanced Trade sandbox | Checkouts sandbox |
| --- | --- | --- | --- |
| Login and keys | Separate sandbox login and keys | None | Coinbase Business account; same CDP keys as production |
| Funds | Unlimited fake funds; no transfers | Fixed mocked balances | Testnet USDC on Base Sepolia |
| Market data | Own books, 9 online markets | None (404) | Not applicable |
| Can prove | Signing, order flow, FIX sessions (documented; not tested here) | Response parsing, documented error branches | Checkout and webhook flow |
| Cannot prove | Production prices, depth, slippage | Signing, order logic, state | Real settlement |

Coinbase's Advanced Trade FAQ describes the Exchange APIs as serving institutional clients, with API keys requiring a Coinbase Exchange account. A fourth environment, the CDP Sandbox (`sandbox.cdp.coinbase.com`), simulates custodial accounts and transfers with no blockchain activity. Other venues' testnets are compared in the [paper trading API guide](https://fincodelabs.com/en/blog/paper-trading-api).

## Coinbase Exchange sandbox: login, account and API keys

You sign up separately at the sandbox web interface, create keys there and add fake money from the Portfolios tab; Coinbase's sandbox page says logins and API keys are separate from production.

- **Login.** The page links to `public.sandbox.exchange.coinbase.com`, which on 5 November 2026 answered HTTP 301 to `public-sandbox.exchange.coinbase.com` (200). Documented steps: create an account or sign in, open API from the profile menu, click New API Key. The page does not say who may sign up or whether verification is needed; no account was created for this guide.
- **Funds.** The Deposit button on the Portfolios tab adds unlimited fake funds; Withdraw removes them. The five transfer endpoints, for deposits and withdrawals, are unavailable.
- **Keys.** Signing uses four `CB-ACCESS-*` headers and HMAC-SHA256, as in the sample below; the timestamp must be within 30 seconds of the API's time, and a lost passphrase cannot be recovered. Permissions are View, Trade, Transfer and Manage; see [creating exchange API keys](https://fincodelabs.com/en/blog/exchange-api-key-how-to) and [API key security for trading bots](https://fincodelabs.com/en/blog/api-key-security-trading-bots).

**Exchange sandbox hosts from Coinbase's sandbox page, read 5 November 2026**

| Interface | Sandbox | MiCA sandbox |
| --- | --- | --- |
| REST | `api-public.sandbox.exchange.coinbase.com` | `api-us.dma.sandbox.prime.coinbase.com` |
| WebSocket feed | `ws-feed-public.sandbox.exchange.coinbase.com` | `ws-us.dma.sandbox.prime.coinbase.com` |
| FIX order entry | `fix-ord.sandbox.exchange.coinbase.com:6121` | `fix-us.dma.sandbox.prime.coinbase.com:7110` |

The page also lists direct WebSocket, FIX market data and drop copy hosts for each column, plus a certificate FIX clients must validate. That certificate expired on 25 April 2023; on 5 November 2026 both order-entry hosts above presented newer, valid ones in a TLS handshake, so do not pin it. The page says MiCA clients must use the second column but does not define who counts as one; this guide makes no claim about EU law. Both REST hosts answered without a key, with the same product list and BTC-USD trade IDs from one sequence.

## Coinbase sandbox API: what answered on 5 November 2026

Public Exchange sandbox endpoints answered without a key, private ones returned errors worth knowing in advance, and the market was far thinner than production.

**Requests without an account, 5 November 2026, 19:54 to 20:02 UTC**

| Request | Result |
| --- | --- |
| `/time`, `/products/BTC-USD`, ticker, level 1 book, candles, WebSocket ticker | Answered normally |
| `/products` | 13 products, 9 online; production 845, 516 online |
| BTC-USD spread, ten samples, 20:00 to 20:02 | 10.28 to 427.49 USD; production 0.01 to 2.88 USD |
| BTC-USD 24-hour volume, 20:01 | 376.46 BTC; production 13,434.06 BTC |
| `GET /accounts`, unsigned | 401 `Unauthorized.` |
| Same, signed with a random unregistered key | 500 `Internal Server Error.` in every try |
| Same, timestamp 40 seconds old | 401 `request timestamp expired` |

A wrong key produced a server error rather than a 401, so a client that retries every 5xx would retry a credentials problem forever; this is observed, not documented, behavior and may change.

> **Hypothetical example.** A server's clock runs 40 seconds slow. Public calls keep working, but every signed request falls outside the 30-second window and returns 401 `request timestamp expired`. A startup check against `/time` with a margin you choose, such as 25 seconds (illustrative, not a Coinbase figure), catches it before any order.

## Coinbase Advanced Trade sandbox: fixed data, retired endpoints included

The Advanced Trade sandbox returns the same canned data to every caller, so it checks how your code reads responses, not how it trades.

- **Static.** `GET /accounts` returned four accounts (100 USDC, 1 ETH, 100 USD, 0.5 BTC), identical on a second call, and `POST /orders` with an empty body returned success.
- **Coverage.** The page's note says Accounts and Orders only, but its 18-row table adds Portfolios and Perpetuals. All 10 GET rows returned 200, the `/intx` ones with the INTX portfolio's UUID; of the 8 POST rows, 6 returned 200 and the two `/intx` ones 400 without `portfolio_uuid` and, with it, 404 `This endpoint has been retired.` `/products` returned 404.
- **Retired endpoints still mocked.** Coinbase's Advanced Trade REST page says INTX perpetuals trading ended on 1 October 2026 and the `/intx/*` endpoints are retired. The sandbox still served a mocked ETH-PERP-INTX position on 5 November 2026, so a test that passes there says nothing about production. Perpetual futures are leveraged derivatives and carry a high risk of fast, large losses.

JWT signing, orders, rate limits and the `X-Sandbox` error triggers are covered in the [Coinbase Advanced Trade API Python guide](https://fincodelabs.com/en/blog/coinbase-advanced-trade-api-python).

## Coinbase Pro sandbox: what the old hosts do now

Coinbase Pro is gone, but its old sandbox API host still answered, and its old web address now leads to a production page.

Coinbase's Advanced Trade FAQ says Pro was disabled and all customers migrated as of 1 December 2023, and that Pro API keys cannot trade on Advanced Trade. On 5 November 2026:

- `api-public.sandbox.pro.coinbase.com` answered with the same 13 products and ticker as the Exchange sandbox. No page read for this guide lists it, so it can vanish without notice.
- `public.sandbox.pro.coinbase.com`, the old sandbox web address, answered 301 to `www.coinbase.com/advanced-trade/spot/BTC-USD`, a production trading page. An old tutorial can put you on the live site.

The sample below refuses any host not on its sandbox list and follows no redirects.

## Coinbase Commerce sandbox and the Checkouts API sandbox

No Commerce sandbox page was found in Coinbase's developer documentation on 5 November 2026, only a guide for migrating from Commerce to the Checkouts API, which has one.

- **Migration.** The base URL moves from `api.commerce.coinbase.com` to `business.coinbase.com/api/v1/checkouts`, authentication moves to CDP API keys with JWT Bearer tokens, and the guide suggests testing in the sandbox. It gives no end date for Commerce; its FAQ says existing Commerce webhooks keep working for the Charge API.
- **Checkouts sandbox.** Insert `/sandbox` into the path (`business.coinbase.com/sandbox/api/v1/checkouts`) and use the same CDP keys. Payments arrive in USDC on Base Sepolia; the portal faucet gives 1 testnet USDC per claim, 10 claims per 24 hours. Webhook subscriptions need the label `sandbox` set to `true` or they receive only production events. Refunds are capped at 2.00 USD and data is purged after 30 days.
- **Observed.** Both Checkouts URLs returned 401 without a key. On 5 November 2026 the Commerce FAQ page returned HTTP 502 at every attempt and `api.commerce.coinbase.com/charges` HTTP 530: one day's observation, not evidence that Commerce has closed.

## Testing a Coinbase Exchange sandbox client in Python

Guard the host, check the clock, sign as documented and keep error classes apart; this ran against the public Exchange sandbox on 5 November 2026 (Python 3.11.3, requests 2.31.0).

```python
import base64, hashlib, hmac, json, os, time
from decimal import Decimal, InvalidOperation
import requests

SANDBOX = "https://api-public.sandbox.exchange.coinbase.com"
SANDBOX_HOSTS = {SANDBOX, "https://api-us.dma.sandbox.prime.coinbase.com"}

class AuthError(Exception): pass
class ApiError(Exception): pass

class SandboxClient:
    def __init__(self, base=SANDBOX, key="", secret="", passphrase=""):
        if base not in SANDBOX_HOSTS:                     # never reach production by mistake
            raise ValueError(f"not a sandbox host: {base}")
        self.base, self.key, self.passphrase = base, key, passphrase
        self.secret = base64.b64decode(secret) if secret else b""

    def call(self, method, path, body=None, signed=False, ts=None):
        data, headers = (json.dumps(body) if body else ""), {"Content-Type": "application/json"}
        if signed:
            if not (self.key and self.secret and self.passphrase):
                raise AuthError("key, secret or passphrase missing")
            ts = ts or str(time.time())
            mac = hmac.new(self.secret, (ts + method + path + data).encode(), hashlib.sha256)
            headers |= {"CB-ACCESS-KEY": self.key, "CB-ACCESS-TIMESTAMP": ts,
                        "CB-ACCESS-SIGN": base64.b64encode(mac.digest()).decode(),
                        "CB-ACCESS-PASSPHRASE": self.passphrase}
        r = requests.request(method, self.base + path, data=data or None, headers=headers,
                             timeout=10, allow_redirects=False)  # signed headers stay on this host
        try:
            payload = r.json()
        except ValueError:
            payload = None
        msg = payload.get("message", "") if isinstance(payload, dict) else ""
        if r.status_code == 401:
            raise AuthError(msg)
        if r.status_code >= 300 or payload is None:  # signed 500: check the key, do not retry
            raise ApiError(f"HTTP {r.status_code} {msg}")
        return payload

def to_increment(value, step):
    try:
        d, step = Decimal(value), Decimal(step)
        ok = d.is_finite() and d > 0 and d == d.quantize(step)
    except (InvalidOperation, TypeError):
        ok = False
    if not ok:
        raise ValueError(value)
    return format(d.quantize(step), "f")

c = SandboxClient()
print("clock skew under 30 s:", abs(c.call("GET", "/time")["epoch"] - time.time()) < 30)
btc = c.call("GET", "/products/BTC-USD")
print(btc["id"], btc["status"], to_increment("1E+2", btc["quote_increment"]))
for bad in ["1e400", "1e-400", "nan", "0.000000001"]:
    try:
        to_increment(bad, btc["base_increment"])
    except ValueError:
        print("rejected", bad)
fake = dict(key=os.urandom(16).hex(), secret=base64.b64encode(os.urandom(64)).decode(),
            passphrase="synthetic")
for client, ts in [(SandboxClient(), None), (SandboxClient(**fake), None),
                   (SandboxClient(**fake), str(time.time() - 3600))]:
    try:
        client.call("GET", "/accounts", signed=True, ts=ts)
    except (AuthError, ApiError) as err:
        print(type(err).__name__, err)
try:
    SandboxClient(base="https://api.exchange.coinbase.com")
except ValueError as err:
    print(err)
```

Output:

```
clock skew under 30 s: True
BTC-USD online 100.00
rejected 1e400
rejected 1e-400
rejected nan
rejected 0.000000001
AuthError key, secret or passphrase missing
ApiError HTTP 500 Internal Server Error.
AuthError request timestamp expired
not a sandbox host: https://api.exchange.coinbase.com
```

The signed calls use a random key made at run time, so they test only error paths: missing credentials stop before any network call, the unregistered key gets the 500, the stale timestamp the 401. A successful signed request needs a sandbox account's key and was not run. Amounts stay strings: `1e400`, `1e-400`, `nan` and sizes finer than `base_increment` are refused rather than sent as infinity or zero, and `1E+2` goes out as `100.00`. Redirects are refused because requests 2.31.0, by default, passed all four `CB-ACCESS-*` headers to the host a 301 named in a local mock test.

Retry design is in [crypto exchange API integration](https://fincodelabs.com/en/blog/crypto-exchange-api-integration) and limits for live tests in [trading bot risk management](https://fincodelabs.com/en/blog/trading-bot-risk-management). For integration work in general, see [exchange API integration](https://fincodelabs.com/en/services/exchange-api-integration); naming Coinbase here does not mean Fincode integrates it or has built on it.

## Frequently asked questions

### Is there a Coinbase sandbox login?

Yes, for the Exchange sandbox: a separate sign-up at public.sandbox.exchange.coinbase.com, which redirected to public-sandbox.exchange.coinbase.com on 5 November 2026. The Advanced Trade sandbox has no login.

### Can I use my Coinbase API key in the sandbox?

Not in the Exchange sandbox, whose keys are separate from production. The Advanced Trade sandbox needs no key, and the Checkouts sandbox takes the same CDP keys as production.

### Does the Coinbase sandbox use real market prices?

No. In ten samples on 5 November 2026, 20:00 to 20:02 UTC, the Exchange sandbox BTC-USD spread ranged from 10.28 to 427.49 USD, against 0.01 to 2.88 USD in production; Advanced Trade sandbox values are fixed.

### Does the Coinbase Pro sandbox still work?

Coinbase says Pro was disabled and all customers migrated as of 1 December 2023. Its old sandbox API host still answered on 5 November 2026, but no current page read for this guide lists it, so use the documented Exchange sandbox hosts.

## Sources

- [Coinbase Developer Docs: Exchange Sandbox (hosts, fake funds, unsupported transfers, MiCA hosts)](https://docs.cdp.coinbase.com/exchange/introduction/sandbox)
- [Coinbase Developer Docs: Exchange Systems and Operations (production and MiCA production hosts)](https://docs.cdp.coinbase.com/exchange/introduction/systems-operations)
- [Coinbase Developer Docs: Exchange REST API authentication (CB-ACCESS headers, 30-second window)](https://docs.cdp.coinbase.com/exchange/rest-api/authentication)
- [Coinbase Developer Docs: Advanced Trade API Sandbox](https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/sandbox)
- [Coinbase Developer Docs: Advanced Trade REST endpoints (INTX retired, 1 October 2026)](https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/rest-api)
- [Coinbase Developer Docs: Advanced Trade API FAQ (Coinbase Pro migration, Exchange clients)](https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/faq)
- [Coinbase Developer Docs: Checkouts API Sandbox Environment](https://docs.cdp.coinbase.com/coinbase-business/checkout-apis/sandbox)
- [Coinbase Developer Docs: Migrate from Commerce, overview](https://docs.cdp.coinbase.com/coinbase-business/checkout-apis/migrate-from-commerce/overview)
- [Coinbase Developer Docs: Migrate from Commerce, FAQ and resources](https://docs.cdp.coinbase.com/coinbase-business/checkout-apis/migrate-from-commerce/faq)
- [Coinbase Developer Docs: CDP Sandbox overview](https://docs.cdp.coinbase.com/get-started/sandbox/overview)
- [Coinbase Exchange sandbox: live public products endpoint](https://api-public.sandbox.exchange.coinbase.com/products)
- [Capital Markets Law No. 6362, Article 99/A (Turkish, consolidated text)](https://www.mevzuat.gov.tr/mevzuatmetin/1.5.6362.pdf)

> This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the [editorial policy](https://fincodelabs.com/en/editorial-policy).

---

Published by Fincode (Fincode Yazılım ve Teknoloji A.Ş.), a software company in Istanbul, Turkey: https://fincodelabs.com/en/blog/coinbase-sandbox

Cite as: Fincode, "Coinbase sandbox: Exchange vs Advanced Trade vs Checkouts", updated November 6, 2026, https://fincodelabs.com/en/blog/coinbase-sandbox
