Published APIs
Published APIs let you expose a flow as an inbound API endpoint. External consumers call your endpoint, data flows through your pipeline, and results are optionally returned synchronously.
Defining a published API
Section titled “Defining a published API”A published API endpoint is defined with:
source: connector: api-gateway trigger: apiThe full published API configuration is managed via the web UI, API, or MCP tools.
API configuration
Section titled “API configuration”| Field | Description |
|---|---|
path | API path (e.g., "partner-orders") |
method | HTTP method: GET, POST, PUT, PATCH, DELETE |
requestSchema | JSON Schema for request validation |
responseSchema | JSON Schema for response (enables synchronous mode) |
responseMapping | Mapping block for response transformation |
authType | api_key, oauth2, or none |
validationMode | strict (reject invalid) or lenient (log and continue) |
Creating via MCP
Section titled “Creating via MCP”{ "name": "create_published_api", "arguments": { "description": "Inbound endpoint for partner order submissions with validation", "example_payload": { "partner_id": "ACME", "order_id": "PO-2024-001", "items": [{"sku": "WIDGET-A", "qty": 10}] } }}The AI generates the API configuration including request schema, response mapping, and validation rules.
Consumer keys
Section titled “Consumer keys”Each published API can have multiple consumer keys for authentication and tracking:
Consumer keys are stored in the consumer_api_keys table. Keys are SHA-256 hashed at rest — fyrn never stores the raw key after initial creation. Each key has a human-readable prefix (e.g., fyrn_ck_acme_) so you can identify the consumer from logs without exposing the secret.
Creating a key
Section titled “Creating a key”fyrn api keys create \ --api partner-orders \ --consumer "ACME Corp" \ --rate-limit 50/s \ --daily-limit 100000The CLI returns the full key once. Store it securely — it cannot be retrieved again.
Consumer key created: Key: fyrn_ck_acme_sk_a1b2c3d4e5f6... Consumer: ACME Corp Rate limit: 50 req/s, 100,000 req/day Status: activeRotating a key
Section titled “Rotating a key”Rotation creates a new key and deactivates the old one. You can set a grace period during which both keys are accepted:
fyrn api keys rotate \ --api partner-orders \ --consumer "ACME Corp" \ --grace-period 24hDuring the grace period, both the old and new keys are valid. After it expires, the old key returns HTTP 401.
Rate limiting
Section titled “Rate limiting”Each key tracks requestCount and lastUsedAt. When a consumer exceeds their per-second or daily limit, the API returns HTTP 429 with a Retry-After header.
Key states
Section titled “Key states”| State | Behavior |
|---|---|
active | Accepts requests, counts toward limits |
inactive | Rejects with HTTP 401 — used during rotation grace periods or manual suspension |
Key management
Section titled “Key management”- Create: Generate a new consumer key for a partner
- Rotate: Create a new key and deactivate the old one
- Rate limit: Each key can have per-second and daily limits
- Track usage:
lastUsedAtandrequestCountper key
Request validation
Section titled “Request validation”Strict mode
Section titled “Strict mode”Invalid requests are rejected with HTTP 422:
{ "error": "Validation failed", "details": [ {"field": "items[0].qty", "message": "must be a positive integer"} ]}Lenient mode
Section titled “Lenient mode”Invalid requests are logged but processed. Useful during onboarding when partners are still aligning to the schema.
Versioning
Section titled “Versioning”Published APIs support versioned endpoints so you can evolve schemas without breaking existing consumers.
Version routing
Section titled “Version routing”Consumers specify the version via path prefix:
POST https://api.fyrn.ai/v1/partner-ordersPOST https://api.fyrn.ai/v2/partner-ordersRequests without a version prefix are routed to the latest active version.
Creating a new version
Section titled “Creating a new version”fyrn api versions create \ --api partner-orders \ --version v2 \ --schema ./schemas/partner-orders-v2.jsonThis creates a new version in active state. The previous version remains active until you explicitly deprecate it.
Deprecating a version
Section titled “Deprecating a version”fyrn api versions deprecate \ --api partner-orders \ --version v1 \ --sunset 2026-06-01Deprecated versions continue to serve requests but include a Sunset header and a Deprecation header in every response. Consumers see these in their HTTP responses:
Sunset: Sat, 01 Jun 2026 00:00:00 GMTDeprecation: trueRetiring a version
Section titled “Retiring a version”Once the sunset date passes, retire the version to stop serving requests:
fyrn api versions retire \ --api partner-orders \ --version v1Retired versions return HTTP 410 Gone with a body pointing consumers to the current active version.
| Status | Description |
|---|---|
active | Current version, accepting requests |
deprecated | Still works but sunset date is set |
retired | No longer accepts requests |
Listing published APIs
Section titled “Listing published APIs”{ "name": "list_published_apis", "arguments": {}}{ "name": "call_published_api", "arguments": { "api_path": "partner-orders", "payload": {"partner_id": "ACME", "order_id": "PO-001"} }}Example: Partner order endpoint
Section titled “Example: Partner order endpoint”This example creates an inbound API that accepts partner purchase orders, validates the payload, creates an order in your ERP, and returns an acknowledgment with the internal order ID.
1. Define the flow
Section titled “1. Define the flow”name: partner-order-ingestdescription: Accept partner orders via API and create in ERP
source: connector: api-gateway trigger: api
steps: - name: validate-partner action: lookup connector: postgres params: table: partners match: partner_id: "{{ source.partner_id }}" on_failure: reject
- name: create-order action: create connector: erp params: object: SalesOrder mapping: external_ref: "{{ source.order_id }}" partner_id: "{{ source.partner_id }}" line_items: "{{ source.items }}"
- name: build-response action: transform params: output: status: accepted internal_order_id: "{{ steps.create-order.id }}" received_at: "{{ now() }}"2. Configure the API endpoint
Section titled “2. Configure the API endpoint”{ "name": "create_published_api", "arguments": { "flowName": "partner-order-ingest", "path": "partner-orders", "method": "POST", "authType": "api_key", "validationMode": "strict", "requestSchema": { "type": "object", "required": ["partner_id", "order_id", "items"], "properties": { "partner_id": { "type": "string" }, "order_id": { "type": "string", "pattern": "^PO-\\d{4}-\\d{3,}$" }, "items": { "type": "array", "minItems": 1, "items": { "type": "object", "required": ["sku", "qty"], "properties": { "sku": { "type": "string" }, "qty": { "type": "integer", "minimum": 1 } } } } } }, "responseMapping": "steps.build-response.output" }}3. Send a request
Section titled “3. Send a request”curl -X POST https://api.fyrn.ai/v1/partner-orders \ -H "Authorization: Bearer fyrn_ck_acme_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "partner_id": "ACME", "order_id": "PO-2024-001", "items": [ {"sku": "WIDGET-A", "qty": 10}, {"sku": "WIDGET-B", "qty": 5} ] }'4. Response
Section titled “4. Response”{ "status": "accepted", "internal_order_id": "SO-88291", "received_at": "2026-03-05T14:22:08Z"}If validation fails (e.g., missing items), the API returns HTTP 422 before the flow executes, so no partial processing occurs.
What’s next
Section titled “What’s next”- Creating Flows — Build the flow behind the API
- Batch Processing — Published APIs support batch mode
- MCP Tools —
create_published_api,list_published_apis,call_published_api