Skip to Content
Developers5-Minute API Quickstart

5-Minute API Quickstart

RGL8R’s public API is production-first. This guide walks you through authenticating and running one of three canonical workflows end-to-end using nothing but curl, your integration key, and (for two of them) a sample CSV file.

Prerequisites

You need an integration key. Your RGL8R operator will mint one for you as part of assisted onboarding; the secret is revealed once. If you lose it, ask for a rotation.

Set these environment variables:

# Production-first (default once you are ready to ship) export BASE_URL="https://api.rgl8r.com" # Safe sandbox for development and CI dry-runs # export BASE_URL="https://rgl8r-staging-api.onrender.com" export RGL8R_INTEGRATION_KEY="sk_int_..."

Start on production unless you are explicitly testing destructive flows or building a CI pipeline — staging is a shared sandbox, not the canonical environment. Every integration key is tenant-scoped and only sees data for its own tenant, so pointing at production first is the fast path.

Step 1: Exchange your integration key for a bearer token

Every integration-key client starts here. This is the one piece of auth plumbing you need to get right, and everything else in this quickstart assumes it.

TOKEN_JSON=$(curl -sS -X POST "$BASE_URL/api/auth/token/integration" \ -H "x-api-key: $RGL8R_INTEGRATION_KEY") export RGL8R_BEARER_TOKEN=$(echo "$TOKEN_JSON" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")

The response is:

{ "access_token": "<jwt>", "token_type": "Bearer", "expires_in": 3600, "default_adapter": "catalog-excel" }

Important — short TTL: The Bearer JWT expires after expires_in seconds (typically an hour). Do not cache it indefinitely. When you start seeing 401 INVALID_TOKEN on tenant endpoints, re-run the exchange. A long-running worker should exchange shortly before every workflow or refresh on the first 401. The single most common support ticket is “why am I getting 401s after an hour?” — the answer is always “re-exchange the token.”

Use the token on every tenant call as Authorization: Bearer $RGL8R_BEARER_TOKEN.

Step 2: Pick one of three canonical workflows

WorkflowWhen to use itCompanion contract
A. SIMA screeningYou already have a product catalog loaded and want trade-remedy screening. Smallest workflow — no file upload required.docs/api/public-api-contract-v1.md
B. TRADE feedYou are onboarding a fresh product catalog into RGL8R from a CSV/Excel file and want normalization + classification + apply.docs/api/trade-feed-contract-v1.md
C. SHIP auditYou have carrier invoices to audit for findings and want to run dispute / claim flows.docs/api/ship-finding-contract-v1.md, docs/api/ship-claim-submission-contract-v1.md

Each workflow has a runnable Postman folder, a TypeScript example script, and a Python example script. Pick one and follow the workflow below.

Workflow A — SIMA screening (smallest)

Enqueue, poll, fetch:

ENQUEUE_JSON=$(curl -sS -X POST "$BASE_URL/api/sima/batch" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"skus":null,"runPolicy":"always","screeningAuthority":"US"}') RGL8R_JOB_ID=$(echo "$ENQUEUE_JSON" | python3 -c "import sys,json;print(json.load(sys.stdin)['jobId'])") # Poll until terminal (COMPLETED or FAILED) for i in $(seq 1 40); do JOB=$(curl -sS "$BASE_URL/api/jobs/$RGL8R_JOB_ID" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN") STATUS=$(echo "$JOB" | python3 -c "import sys,json;print(json.load(sys.stdin)['status'])") echo "attempt=$i status=$STATUS" [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ] && break sleep 3 done curl -sS "$BASE_URL/api/sima/results?limit=20" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN"

Full runnable versions:

  • Postman: RGL8R-Agent-Quickstart collection, SIMA Workflow folder (docs/postman/RGL8R-Agent-Quickstart.postman_collection.json)
  • TypeScript: docs/api/examples/rgl8r_quickstart.ts
  • Python: docs/api/examples/rgl8r_quickstart.py

Workflow B — TRADE feed (upload → normalize → apply)

This example uses direct apply — it skips classify-preview and review, going straight from normalized SKUs to catalog apply. For the full classify-preview path with AI classification, see docs/api/trade-feed-contract-v1.md.

# 1. Upload the feed file (bundled sample is at docs/api/examples/fixtures/trade-feed-sample.csv) # originCountry and defaultDestinationCountry are required form fields. # Individual rows can override via CSV columns. UPLOAD=$(curl -sS -X POST "$BASE_URL/api/trade/feeds/upload" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN" \ -F "file=@docs/api/examples/fixtures/trade-feed-sample.csv" \ -F "originCountry=CN" \ -F "defaultDestinationCountry=US") SESSION_ID=$(echo "$UPLOAD" | python3 -c "import sys,json;print(json.load(sys.stdin)['sessionId'])") # 2. Poll session until READY (or PREVIEW_BLOCKED / FAILED) for i in $(seq 1 40); do SESSION=$(curl -sS "$BASE_URL/api/trade/feeds/$SESSION_ID" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN") STATUS=$(echo "$SESSION" | python3 -c "import sys,json;print(json.load(sys.stdin)['status'])") APPLYABLE=$(echo "$SESSION" | python3 -c "import sys,json;print(json.load(sys.stdin).get('applyable',''))") echo "attempt=$i status=$STATUS applyable=$APPLYABLE" [ "$STATUS" = "READY" ] || [ "$STATUS" = "PREVIEW_BLOCKED" ] || [ "$STATUS" = "FAILED" ] && break sleep 3 done # Gate: check terminal status before proceeding if [ "$STATUS" = "FAILED" ]; then echo "Feed session failed. Check the session response for error details." echo "$SESSION" | python3 -m json.tool exit 1 fi if [ "$STATUS" = "PREVIEW_BLOCKED" ]; then ISSUE_COUNT=$(echo "$SESSION" | python3 -c "import sys,json;print(json.load(sys.stdin).get('issueCount',0))") BLOCKING_COUNT=$(echo "$SESSION" | python3 -c "import sys,json;print(json.load(sys.stdin).get('blockingIssueCount',0))") if [ "$APPLYABLE" != "True" ] || [ "$ISSUE_COUNT" != "0" ] || [ "$BLOCKING_COUNT" != "0" ]; then echo "Session is PREVIEW_BLOCKED with issues — operator intervention required." echo "Issues: $ISSUE_COUNT (blocking: $BLOCKING_COUNT). Check GET /api/trade/feeds/$SESSION_ID/issues" echo "Contact your RGL8R operator to acknowledge non-blocking issues." exit 1 fi echo "PREVIEW_BLOCKED but applyable with zero issues — proceeding to direct apply." fi # 3. Fetch ALL normalized SKUs from the session (paginated) # Response shape: { version, count, total, items: [...] } # The endpoint is paginated (offset/limit). Loop until all rows are fetched. APPLY_ROWS=$(python3 -c " import sys, json, urllib.request base = '${BASE_URL}' sid = '${SESSION_ID}' tok = '${RGL8R_BEARER_TOKEN}' all_items, offset, limit = [], 0, 100 while True: url = f'{base}/api/trade/feeds/{sid}/skus?offset={offset}&limit={limit}' req = urllib.request.Request(url, headers={'Authorization': f'Bearer {tok}'}) data = json.load(urllib.request.urlopen(req)) all_items.extend(data.get('items', [])) if len(all_items) >= data.get('total', 0) or not data.get('items'): break offset += len(data['items']) # Build apply rows — map providedHs -> hsCode, productName -> name # ApplyRowSchema fields: sku, name, hsCode, originCountry, destinationCountry rows = [] for s in all_items: row = {'sku': s['sku']} if s.get('productName'): row['name'] = s['productName'] if s.get('providedHs'): row['hsCode'] = s['providedHs'] if s.get('originCountry'): row['originCountry'] = s['originCountry'] if s.get('destinationCountry'): row['destinationCountry'] = s['destinationCountry'] rows.append(row) print(json.dumps({'rows': rows, 'originCountry': 'CN', 'screeningAuthority': 'US'})) ") # 5. Apply curl -sS -X POST "$BASE_URL/api/trade/feeds/$SESSION_ID/apply" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d "$APPLY_ROWS"

Runnable versions:

  • Postman: RGL8R-Agent-Quickstart collection, Trade Feed Workflow folder
  • TypeScript: docs/api/examples/rgl8r_trade_feed_quickstart.ts
  • Python: docs/api/examples/rgl8r_trade_feed_quickstart.py

PREVIEW_BLOCKED handling: If the session reaches PREVIEW_BLOCKED but the response shows applyable: true with issueCount: 0 and blockingIssueCount: 0, proceed directly to the apply step — no operator contact needed. The operator-contact path applies only when there are actual non-blocking issues that need acknowledgement. See docs/api/trade-feed-contract-v1.md for the full state machine and handoff rules.

Workflow C — SHIP audit (upload → finding → dispute → claim)

# 1. Upload a shipment/invoice CSV (bundled sample: docs/api/examples/fixtures/ship-invoice-sample.csv) UPLOAD=$(curl -sS -X POST "$BASE_URL/api/ship/upload" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN" \ -F "file=@docs/api/examples/fixtures/ship-invoice-sample.csv") SHIP_JOB_ID=$(echo "$UPLOAD" | python3 -c "import sys,json;print(json.load(sys.stdin)['jobId'])") # 2. Poll the job until COMPLETED, then list findings for i in $(seq 1 40); do JOB=$(curl -sS "$BASE_URL/api/jobs/$SHIP_JOB_ID" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN") STATUS=$(echo "$JOB" | python3 -c "import sys,json;print(json.load(sys.stdin)['status'])") echo "attempt=$i status=$STATUS" [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ] && break sleep 3 done curl -sS "$BASE_URL/api/ship/findings?limit=20" \ -H "Authorization: Bearer $RGL8R_BEARER_TOKEN" # 3. Dispute a finding, bundle into a claim submission, generate and submit the packet # (see docs/api/examples/rgl8r_ship_quickstart.ts for the full sequence)

Runnable versions:

  • Postman: RGL8R-Agent-Quickstart collection, SHIP Workflow folder
  • TypeScript: docs/api/examples/rgl8r_ship_quickstart.ts
  • Python: docs/api/examples/rgl8r_ship_quickstart.py

Postman: one-step setup for the file workflows

The Postman file-path footgun. Postman resolves multipart form-data file paths relative to the Postman app’s current working directory, not relative to the collection file on disk. That means there is no default value for trade_feed_file_path or ship_invoice_file_path that will work out of the box after import. The curl, TypeScript, and Python examples resolve relative paths correctly; Postman does not.

Before running the Trade Feed Workflow or SHIP Workflow folders in Postman:

  1. Open the RGL8R-Agent-Quickstart (Staging) environment.
  2. Set trade_feed_file_path to the absolute path of docs/api/examples/fixtures/trade-feed-sample.csv in your local checkout. Example on macOS: /Users/you/code/rgl8r-platform/docs/api/examples/fixtures/trade-feed-sample.csv.
  3. Set ship_invoice_file_path to the absolute path of docs/api/examples/fixtures/ship-invoice-sample.csv.
  4. Save the environment.

The SIMA folder does not need file paths and runs with only integration_key and base_url populated.

  • Production-first agent patterns (retry/backoff, polling, error envelopes): docs/api/agent-integration-kit-v1.md
  • Full API contract pack (auth, error taxonomy, compatibility policy): docs/api/public-api-contract-v1.md
  • Companion workflow contracts:
    • TRADE feed: docs/api/trade-feed-contract-v1.md
    • SHIP finding workflow: docs/api/ship-finding-contract-v1.md
    • SHIP claim submission workflow: docs/api/ship-claim-submission-contract-v1.md
  • OpenAPI spec: docs/api/openapi/rgl8r-public-api-v1.2.0.yaml
  • Error codes and envelope format: docs/error-contract.md
  • Integration key management (operator-assisted): docs/integration-keys.md