{"openapi":"3.1.0","info":{"title":"Fretie API","version":"1.0.0","summary":"AI freight-forwarding platform API","description":"Fretie reads freight quote-request emails, matches them against an organization's live rate ledger, prices quotes with margin rules, and pushes bookings to CargoWise/Magaya. This API exposes that surface to machine clients: inbox ingestion, rate ledger, quotes, and customers. All org-scoped routes require a bearer token (OAuth 2.0 client_credentials via POST /auth/token, or an organization API key). Interactive agents should prefer the MCP server at https://mcp.fretie.com/mcp.","contact":{"name":"Fretie","email":"contact@fretie.com","url":"https://fretie.com/contact"},"termsOfService":"https://fretie.com/terms"},"servers":[{"url":"https://api.fretie.com","description":"Production"}],"security":[{"oauth2":[]},{"apiKey":[]}],"tags":[{"name":"meta","description":"Health and discovery"},{"name":"auth","description":"Token issuance for machine clients"},{"name":"ingest","description":"Raw email ingestion"},{"name":"inbox","description":"Quote-request inbox and agent runs"},{"name":"quotes","description":"Priced quotes and public approval links"},{"name":"rates","description":"Rate ledger and surcharges"},{"name":"customers","description":"Customer records"}],"paths":{"/health":{"get":{"operationId":"getHealth","tags":["meta"],"security":[],"summary":"Service health","description":"Liveness probe. Returns ok:true when the API is serving traffic. No authentication required.","responses":{"200":{"description":"Service is healthy.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"service":{"type":"string"}},"required":["ok"]}}}}}}},"/auth/token":{"post":{"operationId":"createToken","tags":["auth"],"security":[],"summary":"Exchange client credentials for a bearer token","description":"OAuth 2.0 client_credentials grant. Accepts JSON or form-encoded client_id/client_secret issued in the WorkOS dashboard for your organization, and returns a bearer access token for the org-scoped endpoints. Authorization-server metadata is published at /.well-known/oauth-authorization-server.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}}},"responses":{"200":{"description":"Token issued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Unsupported grant_type or missing credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid client credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/methods":{"get":{"operationId":"listAuthMethods","tags":["auth"],"security":[],"summary":"List interactive sign-in methods","description":"Returns the interactive sign-in methods the hosted login page offers (subset of: password, google, microsoft, sso, magic). Machine clients should use POST /auth/token instead.","responses":{"200":{"description":"Enabled methods.","content":{"application/json":{"schema":{"type":"object","properties":{"methods":{"type":"array","items":{"type":"string"}}},"required":["methods"]}}}}}}},"/ingest/email":{"post":{"operationId":"ingestEmail","tags":["ingest"],"summary":"Push a raw email into the quote pipeline","description":"Submits an inbound email (from a mail forwarder, Zapier, or a custom integration) to the organization's inbox. Requires a per-connector bearer key. If the message is recognized as a quote request, the autopilot pipeline runs automatically.","security":[{"apiKey":["ingest:write"]},{"oauth2":["ingest:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundEmail"}}}},"responses":{"200":{"description":"Message accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestResult"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inbox":{"get":{"operationId":"listInboxMessages","tags":["inbox"],"summary":"List inbox messages","description":"Returns the organization's inbox messages, newest first.","security":[{"oauth2":["inbox:read"]},{"apiKey":["inbox:read"]}],"responses":{"200":{"description":"Inbox messages.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InboxMessage"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createInboxMessage","tags":["inbox"],"summary":"Add a message to the inbox","description":"Creates an inbox message manually (equivalent to pasting an email). May trigger an automatic agent run that drafts a quote.","security":[{"oauth2":["inbox:write"]},{"apiKey":["inbox:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundEmail"}}}},"responses":{"200":{"description":"Message created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestResult"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inbox/{id}/generate":{"post":{"operationId":"generateQuoteFromMessage","tags":["inbox"],"summary":"Run the quoting agent on a message","description":"Starts the autopilot pipeline for one inbox message: understand the request, match rates, build a priced quote, apply the margin guard, and draft a reply. Returns the agent run id; poll getAgentRun for the timeline and result.","security":[{"oauth2":["inbox:write"]},{"apiKey":["inbox:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Inbox message id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Run started.","content":{"application/json":{"schema":{"type":"object","properties":{"run_id":{"type":"string"}},"required":["run_id"]}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Message not found in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/runs/{id}":{"get":{"operationId":"getAgentRun","tags":["inbox"],"summary":"Get an agent run","description":"Returns one agent run with its step-by-step timeline and, when finished, the ids of the quote and draft reply it produced.","security":[{"oauth2":["inbox:read"]},{"apiKey":["inbox:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Agent run id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRun"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Run not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes":{"get":{"operationId":"listQuotes","tags":["quotes"],"summary":"List quotes","description":"Returns the organization's quotes, newest first, including status and pricing.","security":[{"oauth2":["quotes:read"]},{"apiKey":["quotes:read"]}],"responses":{"200":{"description":"Quotes.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes/{id}":{"get":{"operationId":"getQuote","tags":["quotes"],"summary":"Get a quote","description":"Returns one quote with its provenance record (which rate, surcharges, and margin rule produced the price).","security":[{"oauth2":["quotes:read"]},{"apiKey":["quotes:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The quote.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Quote not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateQuote","tags":["quotes"],"summary":"Update a quote's status","description":"Transitions a quote (e.g. approve, mark sent, accept). Sending an unapproved quote is refused when the organization's approval gate requires sign-off.","security":[{"oauth2":["quotes:write"]},{"apiKey":["quotes:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","approved","sent","accepted","rejected"]}},"required":["status"]}}}},"responses":{"200":{"description":"The updated quote.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Quote not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Transition refused (e.g. approval gate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/quotes/{id}":{"get":{"operationId":"getPublicQuote","tags":["quotes"],"security":[],"summary":"Get a shared quote (public link)","description":"Returns the customer-facing view of a quote shared via its approval link. No authentication — the unguessable id is the capability.","parameters":[{"name":"id","in":"path","required":true,"description":"Public quote id from the approval link.","schema":{"type":"string"}}],"responses":{"200":{"description":"The public quote.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicQuote"}}}},"404":{"description":"Unknown quote id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/quotes/{id}/accept":{"post":{"operationId":"acceptPublicQuote","tags":["quotes"],"security":[],"summary":"Accept a shared quote","description":"Accepts a quote on behalf of the customer via its public approval link, turning it into a booking (and pushing to the connected TMS).","parameters":[{"name":"id","in":"path","required":true,"description":"Public quote id from the approval link.","schema":{"type":"string"}}],"responses":{"200":{"description":"Quote accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}},"404":{"description":"Unknown quote id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rates":{"get":{"operationId":"listRates","tags":["rates"],"summary":"List rates","description":"Returns the organization's rate ledger: lanes, carriers, buy/sell rates, and validity.","security":[{"oauth2":["rates:read"]},{"apiKey":["rates:read"]}],"responses":{"200":{"description":"Rates.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Rate"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createRate","tags":["rates"],"summary":"Create a rate","description":"Adds a rate to the ledger. Newly created rates participate in quote matching immediately (subject to validity dates).","security":[{"oauth2":["rates:write"]},{"apiKey":["rates:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateInput"}}}},"responses":{"200":{"description":"The created rate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rate"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rates/{id}":{"delete":{"operationId":"deleteRate","tags":["rates"],"summary":"Delete a rate","description":"Removes a rate from the ledger. Existing quotes keep their provenance snapshot.","security":[{"oauth2":["rates:write"]},{"apiKey":["rates:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Rate id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers":{"get":{"operationId":"listCustomers","tags":["customers"],"summary":"List customers","description":"Returns the organization's customer records, newest first.","security":[{"oauth2":["customers:read"]},{"apiKey":["customers:read"]}],"responses":{"200":{"description":"Customers.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createCustomer","tags":["customers"],"summary":"Create a customer","description":"Creates a customer record. Quotes reference customers for per-customer margin rules and history.","security":[{"oauth2":["customers:write"]},{"apiKey":["customers:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerInput"}}}},"responses":{"200":{"description":"The created customer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.0 client_credentials against the WorkOS-backed authorization server. Request only the scopes an integration needs (least privilege). Authorization-server metadata: /.well-known/oauth-authorization-server.","flows":{"clientCredentials":{"tokenUrl":"https://api.fretie.com/auth/token","scopes":{"quotes:read":"Read quotes and their provenance","quotes:write":"Update quote status (approve, send, accept)","rates:read":"Read the rate ledger and surcharges","rates:write":"Create and delete rates and surcharges","inbox:read":"Read inbox messages and agent runs","inbox:write":"Submit messages to the inbox and trigger quote generation","customers:read":"Read customer records","customers:write":"Create and delete customer records","ingest:write":"Push raw emails into the ingestion endpoint"}}}},"apiKey":{"type":"http","scheme":"bearer","description":"Organization API key or per-connector ingestion key, sent as a bearer token. Keys are scoped at issuance to the same named scopes as OAuth tokens."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable error message."}},"required":["error"]},"TokenRequest":{"type":"object","properties":{"grant_type":{"type":"string","enum":["client_credentials"],"description":"Only client_credentials is supported."},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["client_id","client_secret"]},"TokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","description":"Lifetime in seconds."}},"required":["access_token","token_type"]},"InboundEmail":{"type":"object","properties":{"from_name":{"type":"string"},"from_email":{"type":"string","format":"email"},"subject":{"type":"string"},"body":{"type":"string","description":"Plain-text email body."},"source":{"type":"string","description":"Origin label, e.g. webhook, zapier, manual."}},"required":["from_email","subject","body"]},"IngestResult":{"type":"object","properties":{"id":{"type":"string","description":"Inbox message id."},"run_id":{"type":["string","null"],"description":"Agent run id when autopilot started automatically."}},"required":["id"]},"InboxMessage":{"type":"object","properties":{"id":{"type":"string"},"from_name":{"type":["string","null"]},"from_email":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"source":{"type":"string"},"status":{"type":"string"},"received_at":{"type":"string","format":"date-time"}},"required":["id","from_email","subject"]},"AgentRun":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["running","succeeded","failed"]},"steps":{"type":"array","description":"Ordered pipeline timeline.","items":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string"},"detail":{"type":["string","null"]}},"required":["name","status"]}},"quote_id":{"type":["string","null"]}},"required":["id","status"]},"Quote":{"type":"object","properties":{"id":{"type":"string"},"customer_id":{"type":["string","null"]},"status":{"type":"string","enum":["draft","approved","sent","accepted","rejected"]},"mode":{"type":"string","description":"ocean | air | road | rail"},"origin":{"type":"string"},"destination":{"type":"string"},"currency":{"type":"string"},"sell_total":{"type":"number"},"buy_total":{"type":"number"},"margin_pct":{"type":"number"},"created_at":{"type":"string","format":"date-time"}},"required":["id","status","origin","destination"]},"PublicQuote":{"type":"object","properties":{"id":{"type":"string"},"company":{"type":"string","description":"Forwarder name shown to the customer."},"options":{"type":"array","description":"Best value / Fastest / Alternative options.","items":{"type":"object","properties":{"label":{"type":"string"},"carrier":{"type":"string"},"transit_days":{"type":["integer","null"]},"total":{"type":"number"},"currency":{"type":"string"}},"required":["label","total","currency"]}},"status":{"type":"string"}},"required":["id","options","status"]},"Rate":{"type":"object","properties":{"id":{"type":"string"},"mode":{"type":"string","description":"ocean | air | road | rail"},"origin":{"type":"string"},"destination":{"type":"string"},"carrier":{"type":"string"},"container_type":{"type":["string","null"]},"buy_rate":{"type":"number"},"sell_rate":{"type":"number"},"currency":{"type":"string"},"valid_from":{"type":["string","null"],"format":"date"},"valid_to":{"type":["string","null"],"format":"date"}},"required":["id","mode","origin","destination","carrier"]},"RateInput":{"type":"object","properties":{"mode":{"type":"string"},"origin":{"type":"string"},"destination":{"type":"string"},"carrier":{"type":"string"},"container_type":{"type":["string","null"]},"buy_rate":{"type":"number"},"sell_rate":{"type":"number"},"currency":{"type":"string"},"valid_from":{"type":["string","null"],"format":"date"},"valid_to":{"type":["string","null"],"format":"date"}},"required":["mode","origin","destination","carrier"]},"Customer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"company":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"phone":{"type":["string","null"]},"notes":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}},"required":["id","name"]},"CustomerInput":{"type":"object","properties":{"name":{"type":"string"},"company":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"phone":{"type":["string","null"]},"notes":{"type":["string","null"]}},"required":["name"]}}}}