# Delivery Status API

Display name is **Delivery Status** (`PRODUCT_DISPLAY_NAME` in [`src/lib/brand.ts`](./src/lib/brand.ts)). Product site: [https://www.deliverystatus.now](https://www.deliverystatus.now) (prefer www; apex redirects). HTTP API for a Meta Muse directory connector.

Base path: `/v1`. Content type: `application/json`.

This is not a merchant Fast/Bolt checkout. v1 tracks a single package for free. Watch-list auth routes exist but are not featured on the marketing site. Shipment insurance is **not offered yet** — `POST /v1/checkout/insure` remains an inert placeholder and is not linked from the site.

Machine-readable spec: [`openapi.yaml`](./openapi.yaml).

## Auth

- `POST /v1/track` — public (freemium single track).
- `POST /v1/checkout/insure` — public stub only (future / not offered yet); persists an `insurance_offers` row only when a valid user token is present.
- `GET /v1/packages` and `POST /v1/packages/watch` — **required** `Authorization: Bearer <access_token>` from the project’s auth provider on project `muse-ship` (`wlihrxvofxwzrnyvxooh`).

The API creates a database client with the caller JWT and the project anon key so row-level security ([RLS](./supabase/migrations/20260919100000_init.sql)) enforces per-user isolation.

## Tracking modes

When a live aggregator API key is configured, real tracking numbers use our live tracking network (primary key preferred, then fallback). Otherwise responses use an in-process mock. Live responses are cached ~30 minutes. `MSHIP-*` scenario codes always use the mock and never call a live aggregator.

| Mode | Notes |
| --- | --- |
| `demo` (mock) | No live aggregator key. Deterministic statuses. Safe for casual visitors and CI. |
| `live` | Aggregator key configured. Courier auto-detect when `carrier` is omitted. Cached ~30 min per number (+ optional carrier). |

Mock scenario codes: `MSHIP-PENDING`, `MSHIP-INFO`, `MSHIP-TRANSIT`, `MSHIP-OFD`, `MSHIP-FAIL`, `MSHIP-DELIVERED`, `MSHIP-PICKUP`, `MSHIP-EXCEPTION`, `MSHIP-EXPIRED`. Any other 4–100 character number maps from its last alphanumeric character when mock is active.

## Normalized status

`pending` · `info_received` · `in_transit` · `out_for_delivery` · `attempt_failed` · `delivered` · `available_for_pickup` · `exception` · `expired` · `unknown`

Aggregator milestones and tags are mapped into this set by the connector normalizers.

## Endpoints

### `GET /v1/health`

Liveness plus whether tracking is live or demo. Does not expose vendor internals.

```json
{
  "ok": true,
  "service": "delivery-status",
  "product": "Delivery Status",
  "tracking": "demo"
}
```

`product` is `getProductDisplayName()` (`PRODUCT_DISPLAY_NAME` or **Delivery Status**). `tracking` is `live` when a live aggregator key is configured, otherwise `demo`.

### `POST /v1/track`

```json
{ "tracking_number": "MSHIP-TRANSIT", "carrier": "ups" }
```

`carrier` is optional. When present it is passed as a courier hint; when omitted the live network auto-detects the courier.

```json
{
  "tracking": {
    "tracking_number": "MSHIP-TRANSIT",
    "carrier": "mock-carrier",
    "status": "in_transit",
    "eta": "2026-09-20",
    "events": [],
    "provider": "mock"
  }
}
```

### `GET /v1/packages`

Lists the caller’s watches joined to `tracked_packages`.

```json
{ "watches": [{ "id": "…", "package": { "tracking_number": "1Z…", "status": "in_transit" } }] }
```

### `POST /v1/packages/watch`

Tracks via the aggregator (with the same mock-scenario + cache rules), upserts `tracked_packages` + `tracking_events`, and creates a `watches` row. Payment gating is **not** enforced in v1.

```json
{ "tracking_number": "MSHIP-DELIVERED" }
```

### `POST /v1/checkout/insure`

**Not offered yet.** Always returns a payment **placeholder** (`checkout_url: null`, `live: false`). Optional body: `tracking_number`, `coverage_cents`. Not linked from the marketing site.

```json
{
  "checkout": {
    "provider": "stripe_link",
    "status": "placeholder",
    "live": false,
    "checkout_url": null,
    "offer": {
      "tracking_number": "MSHIP-TRANSIT",
      "coverage_cents": 10000,
      "premium_cents": 299,
      "currency": "usd"
    },
    "next_step": "Create a payment product/price…"
  }
}
```

## Errors

```json
{ "error": { "code": "invalid_request", "message": "tracking_number is required" } }
```

| code | HTTP |
| --- | --- |
| `invalid_request` | 400 |
| `unauthorized` | 401 |
| `provider_error` | 400 or 502 |
| `not_configured` | 503 |
| `database_error` | 500 |
| `internal_error` | 500 |

## Muse connector description (short)

Submit this API as **Delivery Status** ([https://www.deliverystatus.now](https://www.deliverystatus.now)). Muse-facing copy: “Check with Delivery Status?” It answers with a normalized tracking status. Privacy: [/privacy](/privacy). Terms: [/terms](/terms). Attach those URLs at [muse.ai/platform](https://muse.ai/platform).
