First-time setup

Get started

Follow these steps in order. When you finish, you will have a working project API key and a successful weather + traffic query against the hosted API.

What you will end up with

  • An Atlas One console login (for humans)
  • A project that owns keys and usage
  • A wc_… API key stored in your secrets manager (for your app)
  • A successful POST /v1/context/queries response with a requestId

Setup

One-time account, project, and key setup — do this once per environment.

0. Two planes (read this once)

Atlas One separates people from software:

CONSOLEYou (human)Clerk sign-in sessioncreates projects + keysDATA PLANEYour app (software)wc_… API keyno console session
  • Console (this website) — you sign in, create projects, mint keys, use Playground, watch Usage
  • Data plane (the API at https://world-context.vercel.app) — your backend calls it with a wc_… key. It does not use your console password or email session

If you try to call the API with a Clerk session cookie, it will fail. Apps must use the project key.

1. Create your account

  1. Open Sign up and register with email (or the sign-up options shown)
  2. Verify your email if prompted — unverified accounts may be blocked from creating API keys
  3. After sign-in you should land on Overview. Confirm you see account name, role, and this month’s usage numbers

Already registered? Use Sign in.

2. Create a project

  1. Go to Projects
  2. Create a project with a clear name, for example staging or my-tms-prod
  3. Open the project — you should see an API keys area for that project

Keys and usage are project-scoped. A key from project A cannot read snapshots created under project B. Use separate projects for staging vs production when you can.

3. Mint an API key (shown once)

  1. In the project, create an API key and give it a label you will recognize later (for example local-dev or railway-prod)
  2. A modal appears with the plaintext secret starting with wc_. Copy it immediately
  3. Store it somewhere durable before you close the modal:
    • password manager / secrets vault, or
    • your host’s env vars (Railway, Vercel, AWS Secrets Manager, etc.)
  4. Click “I saved it” only after the secret is stored. Atlas One will never show the plaintext again

Lost the secret? Revoke that key in the console and mint a new one. There is no rotate endpoint in V1 — revoke + create is the path.

Never commit wc_… keys to git, paste them into public Slack, or ship them in a browser frontend. Keep keys on the server.

4. Set environment variables in your app

In the environment where your backend runs, set:

ATLAS_ONE_API_BASE_URL=https://world-context.vercel.app
ATLAS_ONE_API_KEY=wc_your_secret_here

Optional — only if HeftIQ (or your host) gave you a Vercel Deployment Protection bypass secret. Without it, some hosted deployments return an HTML “Authentication Required” page instead of JSON:

VERCEL_AUTOMATION_BYPASS_SECRET=your_bypass_secret

5. Smoke-test: health

Confirm the API is reachable before you debug query bodies.

export ATLAS_ONE_API_BASE_URL='https://world-context.vercel.app'

# If you have a bypass secret, keep this header on every request:
# -H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET"

curl -sS "$ATLAS_ONE_API_BASE_URL/health"

Expect: JSON that indicates the service is up (not an HTML login page). If you see HTML auth, add the bypass header from step 4 and retry.

Query

Resolve weather/traffic/routing/hazard context for a location and time window.

6. First real query (cURL)

This is the Memphis → Atlanta demo (same corridor as Playground). Replace the key with yours.

export ATLAS_ONE_API_BASE_URL='https://world-context.vercel.app'
export ATLAS_ONE_API_KEY='wc_…'

curl -sS -X POST "$ATLAS_ONE_API_BASE_URL/v1/context/queries" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  # -H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET" \
  -d '{
    "kinds": ["weather", "traffic", "routing", "hazard"],
    "location": {
      "kind": "routePlace",
      "origin": "Memphis, TN",
      "destination": "Atlanta, GA"
    },
    "timeWindow": {
      "windowStart": "2026-07-21T12:00:00.000Z",
      "windowEnd": "2026-07-22T12:00:00.000Z"
    },
    "options": {
      "hazard": { "corridorBufferKm": 100 }
    }
  }'

You should get HTTP 200. The top-level envelope always looks like this — one result object per kind you asked for:

{
  "requestId": "req_…",
  "results": [
    { "kind": "weather", "cacheHit": false, "snapshot": { /* see weather below */ } },
    { "kind": "traffic", "cacheHit": false, "snapshot": { /* see traffic below */ } }
  ]
}

Weather snapshot (example)

Live fields live under snapshot.signals. Optional fields may be omitted when the provider did not return them.

{
  "kind": "weather",
  "cacheHit": false,
  "snapshot": {
    "snapshotId": "wctx_…",
    "kind": "weather",
    "providerRef": "open-meteo@1.0.0",
    "providerVersion": "1.0.0",
    "sourceRetrievedAt": "2026-07-21T12:00:00.000Z",
    "expiresAt": "2026-07-21T12:30:00.000Z",
    "locationInput": {
      "kind": "routePlace",
      "origin": "Memphis, TN",
      "destination": "Atlanta, GA"
    },
    "timeWindowInput": {
      "windowStart": "2026-07-21T12:00:00.000Z",
      "windowEnd": "2026-07-22T12:00:00.000Z"
    },
    "signals": {
      "kind": "weather",
      "currentCondition": "Partly cloudy",
      "temperatureC": 24.5,
      "precipitationProbability": 0.2,
      "rainIndicator": false,
      "snowIndicator": false,
      "stormIndicator": false,
      "windSpeedKph": 12,
      "windGustsKph": 22,
      "visibilityM": 10000,
      "snowfallCm": 0,
      "severeWeatherAlert": false,
      "precipitationRisk": 0.15,
      "windRisk": 0.1,
      "visibilityRisk": 0.05,
      "forecastRiskScore": 0.18,
      "routeWeatherExposureScore": 0.22,
      "icingRisk": 0,
      "floodRisk": 0.05
    },
    "severity": { "weatherSeverityScore": 0.15 },
    "confidence": 0.82,
    "freshnessStatus": "fresh",
    "status": "ok",
    "providerFailureState": "none",
    "attribution": {
      "providerName": "Open-Meteo",
      "attributionText": "Weather data by Open-Meteo (https://open-meteo.com)",
      "sourceUrl": "https://open-meteo.com",
      "licenseRef": "https://open-meteo.com/en/license"
    },
    "limitations": [],
    "hashes": {
      "input": "…",
      "output": "…",
      "location": "…",
      "timeWindow": "…"
    }
  }
}

Traffic snapshot (example)

{
  "kind": "traffic",
  "cacheHit": false,
  "snapshot": {
    "snapshotId": "wctx_…",
    "kind": "traffic",
    "providerRef": "tomtom-flow@1.0.0",
    "providerVersion": "1.0.0",
    "sourceRetrievedAt": "2026-07-21T12:00:00.000Z",
    "expiresAt": "2026-07-21T12:10:00.000Z",
    "locationInput": {
      "kind": "routePlace",
      "origin": "Memphis, TN",
      "destination": "Atlanta, GA"
    },
    "timeWindowInput": {
      "windowStart": "2026-07-21T12:00:00.000Z",
      "windowEnd": "2026-07-22T12:00:00.000Z"
    },
    "signals": {
      "kind": "traffic",
      "congestionLevel": 0.35,
      "estimatedDelayMinutes": 12,
      "delayPercent": 0.18,
      "routeDurationMinutes": 380,
      "freeFlowDurationMinutes": 320,
      "routeDistanceMeters": 620000,
      "dataCoveragePercent": 0.98,
      "routeConfidence": 0.91,
      "roadClosureIndicator": false,
      "incidentIndicator": true,
      "incidentCount": 2,
      "routeOriginLabel": "Memphis, TN",
      "routeDestinationLabel": "Atlanta, GA",
      "comparingSummary": "Comparing Memphis, TN → Atlanta, GA",
      "bottleneckSummary": {
        "segmentCount": 3,
        "slowestRelativeSpeed": 0.42,
        "closedOrImpassable": false
      }
    },
    "severity": { "trafficSeverityScore": 0.28 },
    "confidence": 0.88,
    "freshnessStatus": "fresh",
    "status": "ok",
    "providerFailureState": "none",
    "attribution": {
      "providerName": "TomTom",
      "attributionText": "Traffic data © TomTom",
      "sourceUrl": "https://developer.tomtom.com"
    },
    "limitations": [],
    "hashes": {
      "input": "…",
      "output": "…",
      "location": "…",
      "timeWindow": "…"
    }
  }
}

Read results[].snapshot.signals for the human-useful numbers (temp, delay, etc.). Check snapshot.status per kind — HTTP 200 can still mean one kind failed.

Save requestId if something looks wrong — support can use it to trace the call.

Request fields

  • kinds — required. One or both of "weather", "traffic"
  • location — required. Where to evaluate context (see shapes below)
  • timeWindow — required. windowStart / windowEnd as ISO-8601 UTC strings. End must be after start

Location shapes you can use

  • routePlace — place names: { "kind":"routePlace", "origin":"Memphis, TN", "destination":"Atlanta, GA" }
  • place — single named place: { "kind":"place", "query":"Chicago, IL" }
  • point — coordinates: { "kind":"point", "latitude":40.7, "longitude":-74.0 }
  • route — lat/lng endpoints (when you already have coordinates)

HTTP 200 can still mean one kind failed. Always check each result’s snapshot.status (for example weather ready while traffic is failed).

7. TypeScript SDK

Prefer the typed client in app code. Package: @world-context/sdk.

import { AtlasOneClient } from "@world-context/sdk";

const client = new AtlasOneClient({
  baseUrl: process.env.ATLAS_ONE_API_BASE_URL!, // https://world-context.vercel.app
  apiKey: process.env.ATLAS_ONE_API_KEY!,       // wc_…
  // Only if your deployment requires Vercel Deployment Protection:
  // vercelProtectionBypass: process.env.VERCEL_AUTOMATION_BYPASS_SECRET,
});

const result = await client.queryContext({
  kinds: ["weather", "traffic", "routing", "hazard"],
  location: {
    kind: "routePlace",
    origin: "Memphis, TN",
    destination: "Atlanta, GA",
  },
  timeWindow: {
    windowStart: new Date().toISOString(),
    windowEnd: new Date(Date.now() + 86_400_000).toISOString(),
  },
  options: {
    hazard: { corridorBufferKm: 100 },
  },
});

for (const row of result.results) {
  console.log(row.kind, row.snapshot.status, row.cacheHit);
}

8. Optional: try Playground first

If you want to see a successful query before wiring your app:

  1. Open Playground
  2. Select the project that should be billed
  3. Click Run corridor query
  4. Confirm weather, traffic, routing, and hazard panels appear and a request id is shown

Playground uses your console session (no key in the browser) but still meters usage against the project — check Usage afterward.

9. Fetch a snapshot again

From a query response, copy snapshot.snapshotId, then:

curl -sS "$ATLAS_ONE_API_BASE_URL/v1/context/snapshots/<snapshotId>" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY"
  # -H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET"

10. Historical weather

POST /v1/weather/history/query returns past weather observations plus a deterministic period summary for one location — evidence for questions like “was this lane near heavy rain last week,” never a causal claim about a delay or disruption. It is a separate endpoint from /v1/context/queries: historical data is a time series, not a single point-in-time snapshot, so it is not fetchable via GET /v1/context/snapshots or comparable via /v1/context/compare.

curl -sS -X POST "https://world-context.vercel.app/v1/weather/history/query" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "location": { "kind": "point", "latitude": 41.8781, "longitude": -87.6298 },
    "startTime": "2026-07-01",
    "endTime": "2026-07-03",
    "granularity": "hourly",
    "variables": ["temperature", "precipitation", "wind_speed", "weather_code"],
    "timezone": "America/Chicago"
  }'

location is a single point (lat/lng) or a named place (geocoded before the query runs) — there is no route/corridor variant here, unlike /v1/context/queries.

Single date vs. a range

startTime/endTime are always both required. Set them to the same date for one day's data; set them to different dates for a range — up to 31 days at hourly granularity, or 5 years at daily. Both bounds are inclusive:"2026-07-01" .. "2026-07-03" above returns all three days (July 1, 2, and 3), 72 hourly observations. Future dates are rejected outright — the archive typically lags now by about 5 days.

Response (example)

{
  "queryId": "wctx_hist_…",
  "location": {
    "latitude": 41.8781,
    "longitude": -87.6298,
    "timezone": "America/Chicago"
  },
  "requestedPeriod": { "startTime": "2026-07-01T05:00:00.000Z", "endTime": "2026-07-04T05:00:00.000Z" },
  "granularity": "hourly",
  "observations": [
    {
      "observedAt": "2026-07-01T00:00:00-05:00",
      "temperatureCelsius": 25.6,
      "precipitationMm": 0,
      "windSpeedKph": 10.3,
      "weatherCode": 0,
      "classification": "clear"
    }
  ],
  "summary": {
    "minimumTemperatureCelsius": 20.3,
    "maximumTemperatureCelsius": 31.5,
    "averageTemperatureCelsius": 25.3,
    "totalPrecipitationMm": 27.4,
    "adverseConditionIntervals": 19,
    "dominantClassification": "cloudy",
    "missingObservationCount": 0
  },
  "provider": { "name": "open-meteo-historical", "dataset": "era5", "retrievedAt": "2026-07-29T21:00:14.564Z" },
  "freshness": { "dataStatus": "historical", "latestObservationAt": "2026-07-03T23:00:00-05:00" },
  "limitations": []
}

classification (clear / cloudy / rain / heavy_rain / snow / thunderstorm / fog / high_wind / extreme_heat / extreme_cold / unknown) is always present on every observation, independent of which variables you requested — it is a core output of this endpoint, not an echo of a requested field. weatherCode (the provider's raw code) is only present when "weather_code" is itself in variables. Requesting an unsupported variable is a validation error, not a silently dropped field.

Historical data is immutable, so identical requests are cached long-term — a repeat query returns the same observations/summary under a fresh queryId, with no second call to the upstream provider.

Not every requested variable is guaranteed from every provider. visibility has no archive-API equivalent at all, and relative_humidity/surface_pressure/cloud_cover have no daily rollup — these come back as null plus an entry in limitations, never a fabricated value.

Compare

Ask whether one snapshot (or request set) is a material change from another.

11. Compare snapshots (same kind)

Use POST /v1/context/compare when you need to know whether one snapshot is a material change from another. Both sides must be the same kind (for example weather vs weather). You can pass stored snapshotIds from your project, or inline snapshot objects for dry runs.

Tip: Always use https:// for ATLAS_ONE_API_BASE_URL. Plain http:// can 308-redirect and break JSON clients.

# After two queries, copy each snapshot.snapshotId (same kind).
curl -sS -X POST "$ATLAS_ONE_API_BASE_URL/v1/context/compare" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  # -H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET" \
  -d '{
    "baselineSnapshotId": "wctx_…",
    "candidateSnapshotId": "wctx_…"
  }'

Read these fields first:

  • materiallyChanged — whether the engine treats the candidate as a decision-relevant change
  • changeClassifications — why (for example severity_increased)
  • severity (0–1) and severityBand — how large the change is
  • compatibility — soft vs hard scope mismatches (hard mismatches fail the request)

Output hash equality is a fast “identical payload” shortcut for audit — it is not the same as materiality. A provider label change can appear in the report without flipping materiallyChanged.

12. Compare full request sets

A single POST /v1/context/queries can return several kinds under one requestId. Use POST /v1/context/compare-requests to compare two of those request sets (for example “before vs after” for the same corridor).

curl -sS -X POST "$ATLAS_ONE_API_BASE_URL/v1/context/compare-requests" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  # -H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET" \
  -d '{
    "baselineRequestId": "req_…",
    "candidateRequestId": "req_…"
  }'

Query-shape changes such as kind_added / kind_removed are reported, but they alone do not mean the environment got worse — check per-kind materiallyChanged in the response for true signal changes.

Cache hits still attach snapshots to the new requestId, so compare-by-request works even when the second query reused cached weather/traffic.

Operate

Monitor usage, and turn Atlas One from a query API into a monitoring one — webhooks, watches, and MCP.

13. Monitor usage

Open Usage in the console. You will see metered units for the current period, remaining quota, and reset date. When you hit the limit, the API returns a quota error — wait for the period to reset or ask for a higher limit.

14. Webhook endpoints

Register a URL that should receive signed deliveries when a watch (see the next section) detects a material change. You can also manage endpoints from the Projects console — open a project and go to Webhooks.

curl -sS -X POST "https://world-context.vercel.app/v1/webhook-endpoints" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-app.example.com/hooks/atlas-one"}'

The response includes a secret starting with whsec_ shown once, encrypted at rest, and never returned again. Registering an endpoint alone does not activate anything; subscribe a watch to it (next section) to start receiving deliveries.

What a delivery looks like

POST https://your-app.example.com/hooks/atlas-one
Content-Type: application/json
Atlas-One-Event-Id: evt_...
Atlas-One-Timestamp: 1785500000
Atlas-One-Signature: <hex hmac>

{
  "id": "evt_...",
  "type": "context.material_change",
  "createdAt": "2026-07-29T01:00:00.000Z",
  "watchId": "watch_...",
  "runId": "run_...",
  "previousSnapshotId": "snap_...",
  "currentSnapshotId": "snap_...",
  "data": { "comparisonId": "cmp_...", "primaryClassification": "weather_severity_delta", "matchedConditions": ["weather_severity_increased"] }
}

The payload is a notification, not the full signal — fetch GET /v1/context/snapshots/{currentSnapshotId} for the actual weather/traffic/routing/hazard fields.

Verifying the signature

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, timestamp: string, signature: string, secret: string): boolean {
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Sign the raw request body — re-serializing the parsed JSON before verifying will produce a different byte sequence and fail. Note the signature covers the timestamp and body only, not the event id — if your handler needs to reject a specific event id, check it separately from the payload rather than assuming the signature alone binds to it.

15. Watches

A context watch saves a weather/ traffic/routing/hazard query plus a notification policy and re-executes it on a schedule — this is what turns Atlas One from a query API into a monitoring one. (For tariffs / trade regulation, use policy trade watches instead.) Manage context watches from the Projects console, or with the API directly:

curl -sS -X POST "https://world-context.vercel.app/v1/watches" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "I-45 Houston to Dallas weather",
    "query": {
      "kinds": ["weather"],
      "location": {
        "kind": "route",
        "origin": { "latitude": 29.7604, "longitude": -95.3698 },
        "destination": { "latitude": 32.7767, "longitude": -96.7970 }
      },
      "relativeTimeWindow": { "offsetMinutes": 0, "durationMinutes": 360 }
    },
    "policy": {
      "version": "1",
      "refreshEveryMinutes": 60,
      "conditions": [{ "type": "weather_severity_increased", "minimumSeverity": "moderate" }]
    },
    "webhookEndpointId": "whep_..."
  }'

relativeTimeWindow is resolved fresh from “now” on every scheduled run — a watch cannot carry an absolute time window. refreshEveryMinutes must be one of 30, 60, 120, 180, 360, 720, or 1440. Passing webhookEndpointId at creation atomically activates the watch (draft → active) and starts billing its scheduled runs; omit it to save a draft first and activate later:

curl -sS -X POST "https://world-context.vercel.app/v1/watches/$WATCH_ID/webhook-subscriptions" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"webhookEndpointId": "whep_..."}'
draftdefined, not billingactivescheduled runssubscribeunsubscribedeleteddeletedelete

Condition types: weather_severity_increased (optional minimumSeverity: none/low/ moderate/high/critical), route_delay_increased (optional minimumIncreaseMinutes), traffic_jam_added, new_route_hazard_exposure, hazard_no_longer_intersects_route, provider_unavailable, and provider_recovered. A run only delivers a webhook when the comparison is materially changed and at least one condition matches.

Unsubscribing a watch's last active endpoint drops it back to draft and stops scheduled execution immediately — an unsubscribed watch never keeps costing provider spend in the background.

16. Connect an AI agent (MCP)

Atlas One also exposes a Model Context Protocol server at POST https://world-context.vercel.app/v1/mcp — the same project-scoped wc_… API key and usage metering as the REST API, but callable directly by an MCP-aware AI client (Claude Code, Claude Desktop, ChatGPT, Codex, etc.) instead of hand-written HTTP calls.

AI agentClaude Code, ChatGPT…POST /v1/mcpsame wc_… keyas RESTSame servicesauth, scopes,usage metering

Connect from Claude Code

claude mcp add --transport http atlas-one "https://world-context.vercel.app/v1/mcp" \
  --header "Authorization: Bearer wc_your_secret_here" \
  --header "x-vercel-protection-bypass: your_bypass_secret"

Or add it to a project-shared .mcp.json so your whole team picks it up:

{
  "mcpServers": {
    "atlas-one": {
      "type": "http",
      "url": "https://world-context.vercel.app/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${ATLAS_ONE_API_KEY}",
        "x-vercel-protection-bypass": "${VERCEL_AUTOMATION_BYPASS_SECRET}"
      }
    }
  }
}

Use environment-variable placeholders rather than committing raw secrets. Run /mcp inside a Claude Code session (start a new one if the server was just added — servers load at session start) to confirm it shows as connected.

What's available

  • Context atlas_get_capabilities, atlas_query_context, atlas_get_snapshot, atlas_compare_snapshots, atlas_compare_context_requests, atlas_query_historical_weather
  • Watches atlas_list_watches, atlas_get_watch, atlas_create_watch, atlas_update_watch, atlas_subscribe_watch, atlas_unsubscribe_watch, atlas_delete_watch
  • Webhook endpoints atlas_create_webhook_endpoint, atlas_list_webhook_endpoints, atlas_delete_webhook_endpoint (signing secret returned once on create)

Full partner docs: authentication, usage-event rules, catalogs, known limitations, and host certification — see the repo docs/partners/mcp.md.

Ask for atlas_get_capabilities first — it lists every tool, required scope, and provider fact without consuming any metered quota.

Write tools (atlas_create_watch, atlas_subscribe_watch) require an idempotencyKey — a retried call with the same key and the same arguments replays the original result instead of creating a duplicate. atlas_delete_watch additionally requires confirm: true.

We're still relying on Vercel Deployment Protection for some deployments — while that's the case, the MCP endpoint needs the same x-vercel-protection-bypass header shown above (see step 4). Drop it once protection is off, or once you're pointed at an unprotected deployment.

Policy & trade

Query regulatory and trade developments, resolve friendly product names to HS codes, register trade lanes, and get notified when your lanes or domains are exposed — via REST today (console pages for this surface are not shipped yet).

17. Policy events

Physical context (weather/traffic) answers “what is happening on the ground?” Policy events answer “what is changing in tariffs, customs, sanctions, or legislation that could affect trade?” Same wc_… project key; different routes and scopes (policy_events:read).

List events with a filter. Empty body means “show me what this project may see.” Optional domain matches product interest (HS, concepts, industries, or everyday names). Optional include pulls overlays:

curl -sS -X POST "https://world-context.vercel.app/v1/policy-events/query" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": {
      "version": "1",
      "names": ["steel manufacturing"]
    },
    "limit": 10,
    "include": ["probability", "research", "exposures", "hypotheses"]
  }'

Each item is a mediated view — the canonical cluster member you are allowed to see, plus clusterSiblingIds that are also visible to your project. Invisible ids return 404 (no leak of hidden siblings). When a domain filter matches, look for relevance (matched / confidence / matchedBy).

curl -sS "https://world-context.vercel.app/v1/policy-events/$POLICY_EVENT_ID?include=probability,research" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY"

TypeScript SDK

import { AtlasOneClient } from "@world-context/sdk";

const client = new AtlasOneClient({
  baseUrl: process.env.ATLAS_ONE_API_BASE_URL!,
  apiKey: process.env.ATLAS_ONE_API_KEY!,
});

const { items } = await client.queryPolicyEvents({
  domain: { version: "1", names: ["steel manufacturing"] },
  include: ["probability", "research", "exposures", "hypotheses"],
  limit: 10,
});

OpenAPI tag Policy at https://world-context.vercel.app/docs (Swagger UI) lists every policy route interactively.

18. Domain resolve (name → HS)

You do not need to memorize Harmonized System chapters. Resolve a friendly name or industry against a small hermetic catalog (no LLM on this path). Unknown names return matched: false — Atlas One never invents HS codes.

# Autocomplete catalog (steel / aluminum / apparel, …)
curl -sS "https://world-context.vercel.app/v1/policy-domain/concepts" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY"

# Name → concept + HS chapters + expanded domain filter
curl -sS -X POST "https://world-context.vercel.app/v1/policy-domain/resolve" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "steel manufacturing" }'

Use the expanded domain on event query or a domain-target trade watch. Watches store what you wrote; expansion happens at match/query time so catalog growth applies retroactively.

19. Policy trade watches

Separate from context watches (/v1/watches). A policy trade watch notifies a webhook when something material happens for a chosen target. Requires a webhook endpoint first (see §14) and scopes policy_trade_watches:read|write.

Pick exactly one target type:

  • event — a specific policyEventId (material-change → policy.material_change)
  • domain — product/domain interest (discovery → policy.discovered; later changes → policy.material_change)
  • lane — a registered project trade lane (exposure → policy.exposure)

Domain-target example

curl -sS -X POST "https://world-context.vercel.app/v1/policy-trade-watches" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Steel domain watch",
    "webhookEndpointId": "whep_...",
    "target": {
      "type": "domain",
      "domain": {
        "version": "1",
        "names": ["steel manufacturing"]
      }
    }
  }'

Lane-target example

curl -sS -X POST "https://world-context.vercel.app/v1/policy-trade-watches" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CN→US steel lane",
    "webhookEndpointId": "whep_...",
    "target": {
      "type": "lane",
      "projectTradeLaneId": "ptl_..."
    }
  }'

List / get / soft-delete: GET|DELETE /v1/policy-trade-watches and GET /v1/policy-trade-watches/:watchId. Delete sets status to deleted (repeat DELETE → 404).

Managing policy trade watches from the Projects console UI is still deferred — use REST, the TypeScript SDK, or the Policy Events Postman collection.

20. Trade lanes & exposures

Atlas One does not invent your supply chain from policy text. You register known lanes; the platform then matches them against policy scope and stores project-private exposures (and optional impact hypotheses). Scopes: project_trade_lanes:read|write and policy_events:read for exposure reads.

Register a lane

curl -sS -X POST "https://world-context.vercel.app/v1/project-trade-lanes" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "originCountry": "CN",
    "destinationCountry": "US",
    "mode": "ocean",
    "hsCodes": ["7208"],
    "label": "CN→US HRC ocean"
  }'

Preview a match without persisting (handy for demos):

curl -sS -X POST "https://world-context.vercel.app/v1/policy-event-exposures/evaluate" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "policyEventId": "pol_...",
    "tradeLanes": [{
      "originCountry": "CN",
      "destinationCountry": "US",
      "mode": "ocean",
      "hsCodes": ["7208"]
    }]
  }'

List durable exposures / hypotheses for your project:

curl -sS "https://world-context.vercel.app/v1/policy-event-exposures?policyEventId=$POLICY_EVENT_ID" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY"

curl -sS "https://world-context.vercel.app/v1/policy-impact-hypotheses?policyEventId=$POLICY_EVENT_ID" \
  -H "Authorization: Bearer $ATLAS_ONE_API_KEY"

Computing an exposure does not auto-notify. Create a lane-target policy trade watch to receive policy.exposure webhooks after the daily evaluate jobs run.

Reference

Troubleshooting, terminology, and quick links — come back here anytime.

Troubleshooting

HTML “Authentication Required” instead of JSON
The host has Vercel Deployment Protection. Add header x-vercel-protection-bypass with the bypass secret you were given. Retry /health first.
308 Redirecting / broken JSON client
Use https:// in ATLAS_ONE_API_BASE_URL (not http://). Follow redirects only if your client preserves method and body on POST.
401 / unauthorized on /v1/context/queries
Missing or wrong API key. Use Authorization: Bearer wc_… (full secret). Do not use your console password. Confirm the key was not revoked.
400 invalid request
Check JSON: kinds non-empty, timeWindow end after start, location.kind matches the fields you sent (routePlace needs origin + destination strings).
404 on compare / compare-requests
Snapshot or request ids must exist under the same project as your API key. Cross-project ids are treated as not found.
Compare rejects different kinds
POST /v1/context/compare is same-kind only (weather vs weather). To compare a multi-kind query pair, use POST /v1/context/compare-requests with requestIds.
Cannot create an API key in the console
Verify your email, confirm you are in the right account on Overview, and that the project is not archived.
Lost the wc_ secret
Revoke the old key → mint a new one → update ATLAS_ONE_API_KEY in your host. There is no way to reveal the old secret.
HTTP 200 but traffic looks empty / failed
Inspect results[].snapshot.status for each kind. Weather can succeed while traffic fails if the upstream provider is degraded.
Quota / rate limit errors
Check Usage in the console. Slow down retries, wait for the window to reset, or request a higher limit.
400 FUTURE_TIME_RANGE_NOT_ALLOWED or HISTORICAL_DATA_UNAVAILABLE on /v1/weather/history/query
endTime is in the future, or too recent — the archive typically lags now by about 5 days. Pull the range back further.
400 TIME_RANGE_TOO_LARGE on /v1/weather/history/query
Max span is 31 days at hourly granularity, 5 years at daily. Split a longer lookback into daily granularity, or into multiple requests.
404 on /v1/policy-events/:id
Invisible or missing event for this project. Policy data is mediated by visibility — another project's private event looks the same as not found.
403 on policy routes
Your key is missing a policy scope. Default keys include policy_events:read, policy_trade_watches:read|write, and project_trade_lanes:read|write — mint a new key if yours is older.
policy-domain/resolve returns matched: false
The name/industry is not in the hermetic catalog yet. Try GET /v1/policy-domain/concepts, or pass HS codes / concepts directly on the domain filter.

Glossary

Project API key
Your wc_… secret. Authenticates one project on the data plane.
Snapshot
A frozen context result for a location + time window, with id, status, severity, confidence, and freshness.
Kind
Signal category you request: "weather", "traffic", "routing", or "hazard".
Material change
A compare result where materiallyChanged is true — the candidate is decision-relevant vs the baseline, not just any byte difference.
Request set
All snapshots returned under one requestId from POST /v1/context/queries; compared via POST /v1/context/compare-requests.
Cache hit
Atlas One reused a stored snapshot still inside its freshness window instead of calling upstream again.
Freshness
How usable the snapshot is over time (for example fresh, stale, expired) — separate from how severe the weather/traffic is.
Playground actor
Console-signed-in query path. No wc_ key in the browser; usage is still metered.
Historical weather query
POST /v1/weather/history/query — past observations + a summary for one location, evidence only (never a causal claim). A separate time-series endpoint from /v1/context/queries, not comparable or fetchable through the snapshot/compare endpoints.
Policy event
A mediated regulatory/trade development (tariff, notice, bill…). Queried via POST /v1/policy-events/query — never raw global DB rows.
HS code
Harmonized System tariff chapter or line (e.g. 72 = iron/steel). Used in domain filters and trade-lane product scope.
Domain filter
Product/domain interest (HS, concepts, industries, or friendly names) used to query events or create a domain-target policy trade watch.
Policy trade watch
Webhook subscription for policy material change, discovery, or lane exposure — separate from context watches under /v1/watches.
Project trade lane
A caller-registered origin→destination path (optional mode) used to match policy scope into project-private exposures.
Exposure
Project-private match between a policy event's trade scope and one of your registered lanes — list via GET /v1/policy-event-exposures; notify via a lane-target watch.