BerthTime API reference
The BerthTime API tracks ocean shipments by container number, bill of lading or booking number, across carriers, and returns one normalised timeline of DCSA-style events with vessel legs and ETAs. Add a reference with one call; BerthTime detects the reference type and the carrier, fetches the carrier data, keeps it up to date and pushes changes to your webhook.
Authentication
Send an API key as a bearer token: Authorization: Bearer bt_live_.... Company
admins create keys in Settings > API keys; a key is shown once. Scopes are read
and write, and the key's company is the tenant. Errors are RFC 7807
application/problem+json with a request_id; every response carries
X-Request-Id and rate-limit headers (RateLimit-*); over the limit you get
429 with Retry-After.
Quick start
Track a container, bill of lading or booking
curl -X POST https://berthtime.com/api/v1/shipments \
-H "Authorization: Bearer $BERTHTIME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: po-4711" \
-d '{"reference": "MSCU1234566", "customer_reference": "PO-4711"}'
ref_type and carrier (SCAC) are detected when omitted. A BL or
booking brings in all its containers. Pass callback_url to get this shipment's
updates pushed to that URL.
List shipments and read a timeline
curl https://berthtime.com/api/v1/shipments -H "Authorization: Bearer $BERTHTIME_API_KEY"
curl https://berthtime.com/api/v1/shipments/{shipment_id}/events -H "Authorization: Bearer $BERTHTIME_API_KEY"
Lists use cursor pagination (next_cursor → cursor). Reads only
read stored data; they never call a carrier. POST /shipments/{shipment_id}/refresh
asks for a new fetch (rate-limited per shipment).
Webhooks
Register an endpoint with POST /api/v1/webhooks. Every delivery is signed:
BerthTime-Signature: t=<unix>,v1=<hex>, where v1 is
HMAC-SHA256 of t + "." + body with the endpoint secret.
import hashlib, hmac
def verify(secret: str, header: str, body: bytes) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
signed = parts["t"].encode() + b"." + body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
Endpoints
Every public endpoint, grouped as in the interactive reference below. Base path /api/v1.
Meta
Health and service information.
| get | /api/v1/health | Health check |
Auth
Sign up, log in, log out, switch company (web session).
| get | /api/v1/auth/challenge | Proof-of-work challenge |
| post | /api/v1/auth/signup | Create an account |
| post | /api/v1/auth/login | Log in |
| post | /api/v1/auth/logout | Log out |
| post | /api/v1/auth/switch-company | Switch current company |
| post | /api/v1/auth/forgot-password | Request a password reset email |
| post | /api/v1/auth/reset-password | Set a new password with an emailed token |
| post | /api/v1/auth/verify-email | Confirm the email address with the emailed token |
| post | /api/v1/auth/resend-verification | Send the verification email again |
| post | /api/v1/auth/change-email | Change the sign-in email address |
| post | /api/v1/auth/change-password | Change the password |
Account
The current principal.
| get | /api/v1/me | Who am I |
| patch | /api/v1/me | Update my profile |
Companies
Tenants, members, roles and invitations.
| get | /api/v1/companies | List my companies |
| post | /api/v1/companies | Create a company |
| get | /api/v1/companies/{company_id} | Get a company |
| patch | /api/v1/companies/{company_id} | Update a company |
| get | /api/v1/companies/{company_id}/members | List members |
| patch | /api/v1/companies/{company_id}/members/{member_id} | Change a member's role |
| delete | /api/v1/companies/{company_id}/members/{member_id} | Remove a member |
| get | /api/v1/companies/{company_id}/invitations | List invitations |
| post | /api/v1/companies/{company_id}/invitations | Invite someone |
| delete | /api/v1/companies/{company_id}/invitations/{invitation_id} | Revoke an invitation |
| get | /api/v1/invitations/{token} | Preview an invitation (public) |
| post | /api/v1/invitations/accept | Accept an invitation |
API keys
Company API keys (bt_live_...), shown once.
| get | /api/v1/api-keys | List API keys |
| post | /api/v1/api-keys | Create an API key |
| delete | /api/v1/api-keys/{key_id} | Revoke an API key |
Shipments
Tracked shipments, their containers and events.
| get | /api/v1/shipments | List shipments |
| post | /api/v1/shipments | Track a shipment (single or bulk) |
| get | /api/v1/shipments/{shipment_id} | Get a shipment |
| patch | /api/v1/shipments/{shipment_id} | Update a shipment |
| delete | /api/v1/shipments/{shipment_id} | Archive a shipment |
| post | /api/v1/shipments/{shipment_id}/containers | Add container numbers |
| post | /api/v1/shipments/{shipment_id}/refresh | Refresh now |
| get | /api/v1/shipments/{shipment_id}/events | Shipment timeline |
| get | /api/v1/shipments/{shipment_id}/callback-deliveries | Callback delivery log |
Sharing
Public read-only tracking links (/t/{token}): one per shipment, regenerate or disable any time.
| get | /api/v1/shipments/{shipment_id}/share | Get the share link |
| post | /api/v1/shipments/{shipment_id}/share | Create the share link (or return the active one) |
| patch | /api/v1/shipments/{shipment_id}/share | Change share link options |
| delete | /api/v1/shipments/{shipment_id}/share | Disable the share link |
| post | /api/v1/shipments/{shipment_id}/share/regenerate | Regenerate the share link |
| get | /api/v1/public/track/{token} | Public tracking page data |
Reference data
Carrier coverage and reference detection.
| get | /api/v1/carriers | Carrier coverage |
| post | /api/v1/detect | Detect reference type and carrier |
| get | /api/v1/containers/{number} | Look up a container |
Webhooks
Push notifications for shipment changes.
| get | /api/v1/webhooks/callback-secret | Company callback signing secret |
| post | /api/v1/webhooks/callback-secret/rotate | Rotate the company callback secret |
| get | /api/v1/webhooks | List webhook endpoints |
| post | /api/v1/webhooks | Create a webhook endpoint |
| get | /api/v1/webhooks/{webhook_id} | Get a webhook endpoint |
| patch | /api/v1/webhooks/{webhook_id} | Update a webhook |
| delete | /api/v1/webhooks/{webhook_id} | Delete a webhook endpoint |
| post | /api/v1/webhooks/{webhook_id}/test | Send a test event |
| get | /api/v1/webhooks/{webhook_id}/deliveries | Delivery log |
Notifications
Email alert rules, digests, unsubscribe. Mail is sent from automation@berthtime.com.
| get | /api/v1/notification-rules | List alert rules |
| post | /api/v1/notification-rules | Create an alert rule |
| get | /api/v1/notification-rules/{rule_id} | Get an alert rule |
| patch | /api/v1/notification-rules/{rule_id} | Update an alert rule |
| delete | /api/v1/notification-rules/{rule_id} | Delete an alert rule |
| get | /api/v1/email-types | Every email BerthTime sends |
| get | /api/v1/me/notification-preferences | My notification preferences |
| patch | /api/v1/me/notification-preferences | Update my notification preferences |
| put | /api/v1/me/notification-preferences/rules/{rule_id} | Opt in to / out of one alert rule |
| post | /api/v1/me/notification-preferences/test | Send me a test email |
| get | /api/v1/unsubscribe | What an unsubscribe link does (public) |
| post | /api/v1/unsubscribe | Unsubscribe (public, one-click) |
Usage
Plan, billable shipments per month, overage.
| get | /api/v1/usage | Plan and usage for a month |
| get | /api/v1/usage/shipments | Shipments counted in a month |
Billing
Stripe subscription: checkout, customer portal, webhook. 404 when billing is disabled.
| get | /api/v1/billing | Billing status |
| post | /api/v1/billing/checkout | Start a subscription |
| post | /api/v1/billing/portal | Manage billing |
Support
Contact form and support tickets (BT-1001): your company's requests, replies, close / reopen.
| get | /api/v1/support/tickets | Your company's support requests |
| post | /api/v1/support/tickets | New support request |
| get | /api/v1/support/tickets/{ticket_id} | A support request with its thread |
| post | /api/v1/support/tickets/{ticket_id}/messages | Reply |
| post | /api/v1/support/tickets/{ticket_id}/close | Close (solved, no answer needed) |
| post | /api/v1/support/tickets/{ticket_id}/reopen | Reopen |
| post | /api/v1/public/contact | Contact form (creates a ticket) |
| get | /api/v1/public/support/{token} | Ticket thread from an emailed link |
| post | /api/v1/public/support/{token}/messages | Reply from an emailed link |
Branding & portal
White-label branding, the customer tracking portal (/p/{slug}) and custom domains (Business and up; domains: Scale).
| get | /api/v1/branding | Branding and portal settings |
| put | /api/v1/branding | Update branding and portal settings |
| post | /api/v1/branding/logo | Upload the logo |
| delete | /api/v1/branding/logo | Remove the logo |
| put | /api/v1/branding/domain | Set the custom portal domain |
| delete | /api/v1/branding/domain | Remove the custom domain |
| post | /api/v1/branding/domain/verify | Check the DNS records now |
| get | /api/v1/public/portal/{slug} | Customer portal (public) |
| post | /api/v1/public/portal/{slug}/search | Search a portal |
| get | /api/v1/public/logo/{sha256} | Logo image (public) |
| get | /api/v1/public/portal-by-host | Portal slug for a custom domain |
| get | /api/v1/public/domain-allowed | Caddy on-demand TLS ask endpoint |
MCP
Model Context Protocol server for AI assistants.
| post | /api/v1/mcp | MCP server (Streamable HTTP) |
Interactive reference
Try the endpoints below with your API key (Authorize).