# Getting Started

Follow this path when connecting a new app or testing an integration in
sandbox.

## 1. Choose an environment

Store the base URL and token outside your source code.

```bash
export STALLION_BASE_URL="https://ship.stallion.ca/api/v5"
export STALLION_TOKEN="your_v5_token"
```

Use `https://sandbox.stallion.ca/api/v5` until your request bodies, error
handling, and label-printing flow work end to end.

## 2. Create a token

Create your first v5 token in the dashboard under
**Settings -> Integrations -> API**. Select only the scopes your integration
needs and copy the token when it is shown.

For automated token rotation, create a token with `tokens:manage`, then use
`POST /tokens` from the [API Reference](/openapi#tag/Tokens).

## 3. Pick scopes

Start with the smallest useful scope set:

| Workflow | Typical scopes |
|  --- | --- |
| Quote rates only | `rates:read` |
| Create shipments and quote rates | `shipments:write`, `rates:read` |
| Buy labels | `shipments:write`, `rates:read`, `labels:create` |
| Schedule pickups | `pickups:write` |
| Track shipments | `tracking:read` |
| Update product customs data | `products:read`, `products:write` |
| Classify and approve DDP products | `products:read`, `products:classify`, `products:approve` |
| Quote and book LTL freight | `ltl:read`, `ltl:write` |


See [Authentication & Scopes](/authentication-scopes) for the full scope
model.

## 4. Make a test request

```bash
curl "$STALLION_BASE_URL/shipments?per_page=5" \
  -H "Authorization: Bearer $STALLION_TOKEN" \
  -H "Accept: application/json" \
  -H "User-Agent: MyApp-Integration/1.0"
```

A successful list response returns `data`, `meta`, and `links`.

Send a `User-Agent` header that names your integration (for example
`MyApp-Integration/1.0`). The API sits behind Cloudflare, which refuses a
handful of generic client signatures outright with an HTML `403` and
`error code: 1010` before the request reaches Stallion. Requests that carry an
`Authorization` header are exempt from that check, but a named agent still
makes your traffic easy to identify in support conversations and rate-limit
reviews. Python's `urllib` default agent is one of the refused signatures;
`requests` is not.

## 5. Send JSON requests

For endpoints with a request body, include `Content-Type: application/json`.

```bash
curl -X POST "$STALLION_BASE_URL/rates" \
  -H "Authorization: Bearer $STALLION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "to_address": {
      "name": "Jane Doe",
      "address1": "123 Main St",
      "city": "Toronto",
      "province_code": "ON",
      "postal_code": "M5V 2T6",
      "country_code": "CA"
    },
    "packages": [
      { "weight": 0.5, "weight_unit": "lbs", "package_contents": "T-shirt" }
    ]
  }'
```

Use the returned `service` value when you buy a label.