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

# Environments & Versioning

> Base URLs, how endpoint versioning works, and the one path that doesn't follow the standard contract.

## Base URL

| Environment | Base URL                 |
| ----------- | ------------------------ |
| Production  | `https://api.spenza.com` |

<Warning>
  **No sandbox environment yet.** A separate sandbox/staging base URL isn't available yet. Until it ships, every request in this documentation — and every request your integration makes — hits production. See **[Guides → Testing and validation guidance](/guides#testing-and-validation-guidance)** for how to validate an integration safely without one.
</Warning>

## How versioning works

The current, canonical surface lives under **`/api/v1.1`** — nearly every endpoint in the API Reference is on this path. There is no `Prefer`-header async negotiation and no separate `/api/v1` (non-`.1`) surface; that design was proposed at one point but was never built, so don't look for it.

A small number of operations instead live on **`/api/v3`** — these are the **asynchronous variant** of an operation that also has a synchronous `v1.1` counterpart with a different request/response contract:

| Synchronous (`/api/v1.1`)                                                   | Asynchronous (`/api/v3`)                                                    |
| --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `POST /api/v1.1/plans/purchase` — blocks, returns the finished subscription | `POST /api/v3/plans/purchase` — returns `202` + `transactionId` immediately |

eSIM provisioning (`POST /api/v1.1/esim`) is a partial exception: it's the current canonical path, but it's **always** asynchronous (`202` + `transactionId`) regardless of path — there's no synchronous eSIM provisioning endpoint. See **[Core Concepts → Async operations](/core-concepts#async-operations)** for the full `transactionId`/polling model.

## One documented exception: port-in submission

`POST /api/v3/port-in` (submitting a port-in) is the one operation in this API that doesn't follow the standard contract at all:

* It requires an **account role** (`Admin`, `Super Admin`, or `Standard Admin`) rather than just a valid bearer token.
* Its response is a **flat** `{ success, transactionId, statusEndpoint, message, timestamp }` — no `data` wrapper.
* A synchronous validation error's `error` field is a **plain string**, not `{ code, message }`.

This isn't a bug carried over from an old version — it's simply never been migrated onto the standard envelope. See the operation's page in the API Reference for its exact shape, and **[Numbers & Port-in](/guides#porting-in-an-existing-number)** in the Guides.

## Backward compatibility

The response envelope (`{ success, data, meta }` / `{ success: false, error }`), pagination shape, and field-naming conventions are consistent by design across every standard endpoint — see **[Core Concepts](/core-concepts)**. No formal backward-compatibility guarantee (for example, "fields are never removed within a version") is published for field-level payload changes — check the API Reference against your integration periodically rather than only at initial build time.

## Next steps

* **[Core Concepts](/core-concepts)** for the envelope, pagination, and async pattern that stay constant across endpoints.
* **API Reference** (sidebar) for the current, canonical set of endpoints.
