Configuration Transfer API¶
The Configuration Transfer API allows exporting and importing Floh configuration entities as portable JSON documents. This enables environment migration, backup/restore, version-controlled configuration, and AI-driven automation.
Overview¶
Configuration entities are portable, definition-level objects that describe how your Floh instance is set up — as opposed to transactional data (workflow runs, approvals, audit logs) which represent runtime state.
Exportable Entity Types¶
| Entity Type | JSON Key | Description |
|---|---|---|
| Connectors | connectors |
External system integrations (Authifi, HTTP, etc.) |
| Projects | projects |
Containers for workflow sets (includes nested workflow sets) |
| Email Templates | emailTemplates |
Notification email templates |
| Document Templates | documentTemplates |
Document template metadata (binary files not included) |
| User Groups | userGroups |
Groups used for approval routing |
| Organizations | organizations |
Organization hierarchy and memberships |
| Entitlements | entitlements |
Entitlement definitions linked to connectors |
| Roles | roles |
Role definitions with linked entitlements |
| Workflows | workflows |
Workflow definitions (steps, variables, triggers) |
| Schedules | schedules |
Cron-based scheduled triggers for workflows |
Key Design Principles¶
- Name-based references: Cross-entity references use names (not UUIDs) for portability across environments
- Human-editable JSON: The format is designed for manual editing and version control
- Secrets excluded: Connector secrets (
connector_config) are never included in exports - Optional sections: Each entity section is optional — export/import only what you need
- Dependency resolution: Imports process entities in dependency order automatically
Permissions¶
| Permission | Granted To | Description |
|---|---|---|
config:export |
admin, resource_manager |
Export configuration entities |
config:import |
admin |
Import configuration entities (destructive operation) |
Endpoints¶
GET /api/config/export¶
Export all (or filtered) configuration entities as a JSON document.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
entities |
string | (all) | Comma-separated list of entity types to include |
Example Request:
# Export everything
curl -b cookies.txt http://localhost:3000/api/config/export
# Export only workflows, roles, and connectors
curl -b cookies.txt \
'http://localhost:3000/api/config/export?entities=workflows,roles,connectors'
Example Response:
{
"version": "1",
"exportedAt": "2026-03-08T12:00:00.000Z",
"exportedBy": "admin@example.com",
"entities": {
"connectors": [
{
"name": "authifi-prod",
"type": "authifi",
"description": "Production Authifi instance",
"version": "1.0.0",
"configSchema": { "commands": { "addToGroup": { "params": ["groupId", "userId"] } } },
"enabled": true
}
],
"projects": [
{
"name": "Onboarding",
"description": "User onboarding workflows",
"workflowSets": [
{ "name": "Standard", "description": "Standard onboarding flows" }
]
}
],
"workflows": [
{
"name": "User Onboarding",
"description": "Onboard new users with DUA and training",
"project": "Onboarding",
"workflowSet": "Standard",
"category": "user",
"status": "active",
"subjectVariable": "user",
"trigger": { "types": ["manual"] },
"variables": [
{ "name": "user", "type": "user", "required": true }
],
"steps": [
{ "id": "start", "name": "Start", "type": "start", "config": {}, "transitions": [{ "on": "success", "goto": "send-invite" }] },
{ "id": "send-invite", "name": "Send Invitation", "type": "notification", "config": { "recipientId": "{{user}}" }, "transitions": [{ "on": "success", "goto": "end" }] },
{ "id": "end", "name": "End", "type": "end", "config": {}, "transitions": [] }
],
"onError": "stop",
"debugLogging": false
}
]
}
}
POST /api/config/export¶
Export specific entities selected by name, optionally including their dependencies.
Request Body:
{
"entities": {
"workflows": ["User Onboarding"],
"roles": ["Genome Access Participant"]
},
"includeDependencies": true
}
When includeDependencies is true (default), the export automatically includes entities that the selected ones depend on. For example, exporting a workflow will also export its project, and exporting a role will also export its entitlements and their connectors.
Dependency Chain:
POST /api/config/import/preview¶
Dry-run an import to see what would be created, updated, or skipped — without making any database changes.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
strategy |
string | upsert |
Import strategy (see below) |
Import Strategies:
| Strategy | Behavior |
|---|---|
upsert |
Create new entities and update existing ones (default) |
create_only |
Only create new entities; report errors for any that already exist |
skip_existing |
Create new entities; skip any that already exist |
Request Body: A configuration JSON document (same format as the export response).
Example:
curl -X POST -b cookies.txt \
-H 'Content-Type: application/json' \
-d @config.json \
'http://localhost:3000/api/config/import/preview?strategy=upsert'
Response:
{
"status": "completed",
"summary": {
"created": 3,
"updated": 1,
"skipped": 0,
"errors": 0
},
"details": [
{ "entity": "connector", "name": "authifi-prod", "action": "created" },
{ "entity": "project", "name": "Onboarding", "action": "created" },
{ "entity": "workflow_set", "name": "Onboarding/Standard", "action": "created" },
{ "entity": "workflow", "name": "User Onboarding", "action": "updated" }
]
}
POST /api/config/import¶
Execute an import, applying changes inside a database transaction.
Query Parameters: Same as preview (strategy).
Request Body: A configuration JSON document.
Response: Same format as preview, but changes are persisted to the database.
Import Order (dependency resolution):
- Connectors (no dependencies)
- Projects with nested workflow sets
- Email templates
- Document templates (metadata only — skipped if new)
- User groups (members resolved by email)
- Organizations (parent resolved by name)
- Entitlement definitions (connector resolved by name)
- Role definitions with entitlement links
- Workflow definitions (project + set resolved by name)
- Scheduled triggers (workflow resolved by name)
Response Status Values:
| Status | Meaning |
|---|---|
completed |
All entities processed successfully |
completed_with_errors |
Some entities succeeded, some failed |
failed |
All entities failed |
JSON Document Format¶
The configuration document has this structure:
{
"version": "1",
"exportedAt": "2026-03-08T12:00:00Z",
"exportedBy": "admin@example.com",
"description": "Optional description",
"entities": {
"connectors": [],
"projects": [],
"emailTemplates": [],
"documentTemplates": [],
"userGroups": [],
"organizations": [],
"entitlements": [],
"roles": [],
"workflows": [],
"schedules": []
}
}
All entity sections are optional. You can create a minimal document with just the entities you want to import:
{
"version": "1",
"entities": {
"workflows": [
{
"name": "Simple Approval",
"description": "A simple approval workflow",
"project": "Default",
"workflowSet": "Default",
"category": "general",
"status": "draft",
"subjectVariable": null,
"trigger": { "types": ["manual"] },
"variables": [],
"steps": [
{ "id": "start", "name": "Start", "type": "start", "config": {}, "transitions": [{ "on": "success", "goto": "end" }] },
{ "id": "end", "name": "End", "type": "end", "config": {}, "transitions": [] }
],
"onError": "stop",
"debugLogging": false
}
]
}
}
Entity Schema Reference¶
Connector¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique connector name |
type |
string | Connector type (e.g. authifi, http, ldap) |
description |
string | Human-readable description |
version |
string | Connector version |
configSchema |
object | JSON schema defining the connector's configuration |
enabled |
boolean | Whether the connector is active |
Project¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique project name |
description |
string | Project description |
workflowSets |
array | Nested workflow sets ({ name, description }) |
Email Template¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique template name |
description |
string | Template description |
subjectTemplate |
string | Handlebars subject template |
bodyTemplate |
string | Handlebars body template (HTML) |
isDefault |
boolean | Whether this is the default template |
User Group¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique group name |
description |
string|null | Group description |
members |
string[] | Member email addresses |
Organization¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique organization name |
address |
string|null | Physical address |
website |
string|null | Website URL |
domain |
string|null | Email domain |
parent |
string|null | Parent organization name |
contacts |
array | Contact objects ({ name, email, phone, title }) |
members |
array | Member objects ({ email, role }) where role is member, signatory, or approver |
Entitlement¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique entitlement name |
description |
string|null | Description |
connector |
string | Connector name (resolved by name) |
provisionConfig |
object | Configuration for provisioning |
deprovisionConfig |
object | Configuration for deprovisioning |
reconciliationConfig |
object|null | Configuration for reconciliation |
Role¶
| Field | Type | Description |
|---|---|---|
name |
string | Unique role name |
description |
string|null | Role description |
status |
string | active or inactive |
expiresAfterDays |
number|null | Auto-expiry in days |
entitlements |
string[] | Linked entitlement names |
Workflow¶
| Field | Type | Description |
|---|---|---|
name |
string | Workflow name |
description |
string | Workflow description |
project |
string | Project name (resolved by name) |
workflowSet |
string | Workflow set name within the project |
category |
string | user, group, project, or general |
status |
string | draft, active, or deprecated |
subjectVariable |
string|null | Variable used for run tracking |
trigger |
object | Trigger configuration ({ types: ["manual"|"scheduled"|"webhook"] }) |
variables |
array | Variable definitions |
steps |
array | Step definitions (the workflow graph) |
onError |
string | Error strategy: stop, skip, or retry |
debugLogging |
boolean | Enable debug logging |
Schedule¶
| Field | Type | Description |
|---|---|---|
workflow |
string | Workflow name (resolved by name) |
name |
string|null | Schedule display name |
cronExpression |
string | Cron expression (e.g. 0 2 * * *) |
timezone |
string|null | IANA timezone (e.g. UTC, America/New_York) |
enabled |
boolean | Whether the schedule is active |
variables |
object | Variables passed to workflow runs |
AI Automation Examples¶
Export and save to file¶
Import from file with preview first¶
# Preview
curl -s -X POST -b cookies.txt \
-H 'Content-Type: application/json' \
-d @config-backup.json \
'http://localhost:3000/api/config/import/preview' | jq .
# Apply
curl -s -X POST -b cookies.txt \
-H 'Content-Type: application/json' \
-d @config-backup.json \
'http://localhost:3000/api/config/import?strategy=upsert' | jq .
Create a workflow programmatically¶
cat <<'EOF' | curl -s -X POST -b cookies.txt \
-H 'Content-Type: application/json' \
-d @- \
'http://localhost:3000/api/config/import?strategy=upsert' | jq .
{
"version": "1",
"entities": {
"workflows": [{
"name": "Auto-Generated Approval",
"description": "Created via API",
"project": "Default",
"workflowSet": "Default",
"category": "general",
"status": "draft",
"subjectVariable": null,
"trigger": { "types": ["manual"] },
"variables": [
{ "name": "approver", "type": "user", "required": true }
],
"steps": [
{ "id": "start", "name": "Start", "type": "start", "config": {}, "transitions": [{ "on": "success", "goto": "approve" }] },
{ "id": "approve", "name": "Get Approval", "type": "approval", "config": { "approvers": ["{{approver}}"] }, "transitions": [{ "on": "success", "goto": "end" }] },
{ "id": "end", "name": "End", "type": "end", "config": {}, "transitions": [] }
],
"onError": "stop",
"debugLogging": false
}]
}
}
EOF
Migrate configuration between environments¶
# Export from staging
curl -s -b staging-cookies.txt https://staging.example.com/api/config/export > staging-config.json
# Preview on production
curl -s -X POST -b prod-cookies.txt \
-H 'Content-Type: application/json' \
-d @staging-config.json \
'https://prod.example.com/api/config/import/preview'
# Apply on production (create only — don't overwrite existing)
curl -s -X POST -b prod-cookies.txt \
-H 'Content-Type: application/json' \
-d @staging-config.json \
'https://prod.example.com/api/config/import?strategy=create_only'
Audit Trail¶
All import and export operations are logged in the audit trail:
- Export:
action: "config.exported"with metadata about which entities were exported - Import:
action: "config.imported"with metadata including the strategy used and a summary of created/updated/skipped/errored counts