Agent Developer Guide

Freight Rate Intelligence is designed for AI-first consumption. Every skill is available as a REST endpoint, an MCP tool, and through a unified agent invoke endpoint with full constitutional receipts.

Three Integration Paths

REST API

Standard HTTP endpoints at /v1/* — use from any language or framework.

MCP Tools

Model Context Protocol tools at /mcp — native integration with Claude, Cursor.

Agent Invoke

Unified endpoint at /v1/agent/invoke/:skill_name — consistent envelope for all skills.

Agent Registration

1. Generate an API Key

Sign up for Starter or above, then generate a key from Dashboard → Settings → API Keys. Keys use the fri_ prefix (e.g. fri_abc123...).

Scope your agent’s key to the specific skills it uses. If the agent only calls rate-lookup and market-analysis, a scoped key limits blast radius if the key leaks.

2. Discover Available Skills

curl
$curl https://freightrateintelligence.com/v1/agent/skills \
> -H "Authorization: Bearer fri_your_key_here"

Response:

1{
2 "skills": [
3 {
4 "name": "rate-lookup",
5 "tier_required": "explorer",
6 "description": "Cost-basis rate estimate for any lane"
7 },
8 ...
9 ]
10}

Skill Catalog

SkillTierWhat it does
rate-lookupExplorerCost-basis rate estimate for any lane
diesel-trendExplorerPADD regional diesel price trends
fuel-surchargeExplorerATA/DOE surcharge calculation
market-analysisStarterMacro freight intelligence
lane-comparisonStarterSide-by-side lane comparison
rate-alertsStarterThreshold monitoring
carrier-capacityStarterRegional capacity pressure
audit-reportProfessionalReceipt-chain provenance
rate-forecastProfessionalForward rate projections

Constitutional Commerce

Every agent invocation flows through six stages:

1

Gate

Tier check + rate limit enforcement. Returns 403/429 with clear upgrade info on failure.

2

Handler

Skill execution against real data. Never cached without factor_version + fetch_timestamp.

3

Receipt

Hash-chained receipt generated for the query. Returned as receipt_id in the response.

4

Attribution

AUTH.OBJ record links every data source used to compute the answer.

5

Royalty

ECON.ROY event records the invocation for metered billing.

6

Relay

AGENT.RELAY record captures agent-to-agent tracing for multi-hop chains.

Best Practices

Cache with Factor Versions

Response data includes factor_versions with timestamps. Use these to decide when to refresh — don’t cache blindly by TTL.

1cached = cache.get(key)
2if cached and cached.factor_versions == response.factor_versions:
3 return cached # underlying data hasn't changed

Store Receipts

Keep receipt_id from every call. If a customer disputes a rate six months later, you can replay the exact computation via the audit endpoint.

Handle Tier Errors Gracefully

Some skills require higher tiers. Check the tier_required field from skill discovery before calling, or handle 403 responses with an upgrade nudge.

1if response.status_code == 403:
2 data = response.json()
3 if data.get("error") == "TIER_REQUIRED":
4 prompt_user_to_upgrade(data["required_tier"])

Use Alerts Instead of Polling

The rate-alerts skill monitors lanes and fires webhooks on threshold crossings. Don’t poll rate-lookup in a loop — you’ll burn request quota and get stale signal.

Bulk Discounts on Enterprise

High-volume agents (>50K requests/month) should talk to sales about Enterprise. Per-request pricing drops significantly above the Professional tier.

Example: Multi-Skill Agent

An agent that quotes a reefer lane with market context:

Python
1import requests
2
3HEADERS = {"Authorization": "Bearer fri_your_key_here"}
4BASE = "https://freightrateintelligence.com/v1"
5
6def quote_reefer_lane(origin: str, destination: str):
7 # 1. Cost-basis rate
8 rate = requests.post(f"{BASE}/rates/lookup",
9 headers=HEADERS,
10 json={"origin": origin, "destination": destination, "equipment": "REEFER"}
11 ).json()
12
13 # 2. Market comparison (Starter+)
14 market = requests.post(f"{BASE}/market/analysis",
15 headers=HEADERS,
16 json={"lane": f"{origin} -> {destination}", "equipment": "REEFER"}
17 ).json()
18
19 # 3. Capacity signal
20 capacity = requests.get(f"{BASE}/capacity",
21 headers=HEADERS,
22 params={"region": origin.split(",")[1].strip()}
23 ).json()
24
25 return {
26 "cost_basis": rate["rate_per_mile"],
27 "market_gap_pct": market["gap_pct"],
28 "capacity": capacity["pressure"],
29 "receipts": [rate["receipt_id"], market["receipt_id"], capacity["receipt_id"]],
30 }

Every response carries its own receipt. Storing all three lets you prove exactly what data drove the quote.