FuseBase Demo Organization
Copy to my workspace

T39 Customer API integration guide

Customer API integration guide

Engineers integrating an API at their desks

Customer: Fernbank Logistics Sandbox connected Production keys pending Client-ready

How Fernbank Logistics' engineering team goes from sandbox keys to a live production integration with Relay API, with the code you need at each step. Prepared by your solutions engineer, Devon Marsh.

Environments
Sandbox base URLhttps://sandbox.relayapi.example/v2
Production base URLhttps://api.relayapi.example/v2
Auth methodOAuth 2.0 client credentials, short-lived access tokens
Rate limit600 requests per minute, sandbox and production
Solutions engineerDevon Marsh, integration support through go-live
Target go-liveFriday, Oct 3, 2026

Sample template: the firm, people, clients and figures are fictional and shown for illustration only.

Get connected

✓Create sandbox app and get client credentials
✓Authenticate and fetch shipment data in sandbox
Handle webhooks for shipment status updates
Request production keys and complete the go-live checklist

Step 1: Authenticate

Exchange your client ID and secret for an access token. Tokens expire after 3600 seconds, so cache and refresh them rather than requesting a new one per call.

curl -X POST https://sandbox.relayapi.example/v2/oauth/token \
  -d "grant_type=client_credentials" \
  -d "client_id=fernbank_sandbox_8841" \
  -d "client_secret=REPLACE_WITH_YOUR_SECRET"
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Step 2: Call the shipments endpoint

import requests

headers = {"Authorization": "Bearer " + access_token}
resp = requests.get(
    "https://sandbox.relayapi.example/v2/shipments?status=in_transit",
    headers=headers,
)
print(resp.json())

Same request, your language

curl
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://sandbox.relayapi.example/v2/shipments/SHP-88213"
Python
resp = requests.get(
    f"{BASE_URL}/shipments/SHP-88213",
    headers={"Authorization": f"Bearer {access_token}"},
)
shipment = resp.json()
JSON response
{
  "shipment_id": "SHP-88213",
  "status": "in_transit",
  "carrier": "Northline Freight",
  "eta": "2026-09-25T14:00:00Z",
  "origin": "Columbus, OH",
  "destination": "Reno, NV"
}

Core endpoints

MethodEndpointPurposeAuth scope
POST/oauth/tokenExchange credentials for an access tokennone
GET/shipmentsList shipments, filter by status or dateshipmentsread
GET/shipments/{id}Get one shipment's current detailshipmentsread
POST/shipmentsCreate a new shipmentshipmentswrite
POST/webhooksRegister a webhook endpointwebhookswrite
GET/rate-limitCheck your current usage against the limitnone

Webhook flow for status updates

sequenceDiagram
    participant App as Fernbank app
    participant Relay as Relay API
    participant Carrier as Carrier network
    App->>Relay: POST /oauth/token (client credentials)
    Relay-->>App: access_token, expires_in 3600
    App->>Relay: POST /webhooks (register endpoint)
    Relay-->>App: 201 Created
    Carrier->>Relay: Status update (in transit to delivered)
    Relay->>App: POST to your webhook (signed payload)
    App-->>Relay: 200 OK within 5 seconds

Relay retries a webhook delivery up to 5 times with exponential backoff if your endpoint does not return a 200 within 5 seconds. Verify the X-Relay-Signature header on every payload before trusting it.

Common error codes

CodeMeaningTypical causeWhat to do
401UnauthorizedExpired or missing access tokenRefresh the token, then retry
403ForbiddenToken missing the required scopeRequest the scope from your solutions engineer
404Not foundShipment ID does not exist in this environmentConfirm you are calling sandbox versus production
429Rate limitedOver 600 requests per minuteBack off and retry using the Retry-After header
500Server errorRelay-side issueRetry with backoff; contact support if it persists

Never call production with sandbox credentials, or the reverse

Sandbox and production use separate client IDs, secrets and base URLs. A sandbox credential against the production URL returns 401 and will not silently fall back. Store both sets of credentials in separate secrets, never hardcoded in source.

Go-live checklist

Before you switch to production
✓Sandbox integration handles shipments, webhooks and token refresh
✓Error handling covers 401, 429 and 500 with retry logic
Webhook signature verification implemented and tested
Production client ID and secret requested from Devon Marsh
Load test at expected peak volume, about 4,000 requests per hour

Production keys are issued after a technical review

Devon schedules a 30-minute technical review once the checklist above is complete. Production credentials are issued the same day the review passes. Plan for this before setting a hard go-live date with your own stakeholders.

Next steps

  1. Finish webhook signature verification and confirm it rejects unsigned payloads.
  2. Book the technical review with Devon Marsh once the checklist is complete.
  3. Run the load test and share results before the Oct 3 target go-live.
How to use this template

Duplicate this page per customer integration. Replace the values below from the integration record and your API dashboard; if a value like a target date is not yet agreed, write Unavailable rather than guessing.

VariableMeaningRequired
{{customer.name}}Customer integrating with the APIRequired
{{integration.sandbox_url}}Sandbox base URL for this integrationRequired
{{integration.production_url}}Production base URLRequired
{{integration.solutions_engineer}}Solutions engineer supporting the integrationRequired
{{integration.golive_date}}Target production go-live dateOptional
{{integration.client_id_sandbox}}Sandbox client ID issued to this customerRequired

Never place a live client secret in this document; reference where the customer retrieves it from their own secrets vault.