Skip to content

FlowDrop Orchestration Connector

Exposes FlowDrop workflows to external automation platforms as callable services via Drupal's Orchestration module.

Installation

flowdrop_orchestration_connector requires the Drupal Orchestration module as an additional dependency. This is a separate contrib module not bundled with FlowDrop.

# 1. Install the Orchestration module via Composer
composer require drupal/orchestration

# 2. Enable both modules
drush en orchestration flowdrop_orchestration_connector

# 3. Clear cache
drush cr

The drupal/orchestration package is available on Drupal.org. Verify it is compatible with your Drupal version before installing.

Warning

Running drush en flowdrop_orchestration_connector without first installing drupal/orchestration via Composer will fail with a module-not-found error. Always run composer require drupal/orchestration first.

No service account can be provisioned on orchestration 1.0.0

Orchestration's routes require a permission named use orchestration, but its permissions.yml defines use orchestration connect. The required permission is therefore declared by nothing, and only user 1 — who bypasses permission checks — can reach the API. Granting the permission the module does ship has no effect.

This affects all eight routes and is unfixed at 1.0.x HEAD. Until it is resolved upstream there is no way to authenticate an integration as anything other than user 1.

Overview

The flowdrop_orchestration_connector module makes FlowDrop workflows callable by external automation platforms such as Activepieces, n8n or Zapier. It adds an Orchestration Trigger node; any workflow containing one is published through the Orchestration services API, where an external platform can discover it, invoke it with a payload, and collect the result.

This module is an adapter. It translates between the Orchestration API and FlowDrop's trigger system and does nothing else — it holds no business logic, validates nothing, and dispatches no outbound HTTP. A narrow surface that always works is worth more here than a wide one that sometimes does. What it deliberately omits is listed under What this module does not do.

This module covers the inbound direction only: an external platform starting a FlowDrop run. For the opposite direction — a running workflow calling an external system and pausing until it answers — see the Call and Wait node in flowdrop_interrupt.

Every rule on this page is pinned in the specification registry under RT-OCX.

Dependencies

Usage

For workflow authors

  1. Create a workflow.
  2. Add an Orchestration Trigger node as its entry point.
  3. Configure the expected payload schema and the orchestrator settings.
  4. The workflow is now discoverable by external platforms.

The payload arrives at the trigger node's data.payload output.

Service discovery

GET /orchestration/services
Authorization: Basic <credentials>

Returns every enabled workflow with an enabled orchestration trigger, along with its declared configuration schema.

Executing a workflow

POST /orchestration/service/execute
Authorization: Basic <credentials>
Content-Type: application/json

{
  "id": "flowdrop::my_workflow__node_abc123",
  "config": {
    "payload": { "title": "…", "body": "…" }
  }
}

The response is immediate, and its status is one of three values:

status Meaning
completed Final. results holds the workflow output.
interrupted The run paused — for a human decision, or an external call. results holds what completed so far; metadata.interrupt.interrupt.id identifies the interrupt.
queued Accepted for asynchronous execution; nothing has run yet.

For the latter two, keep execution_id and poll for the result.

execution_id is the correlation key

It is the pipeline entity id on every orchestrator, and it is the same identifier the poll response returns as pipeline_id. One field correlates a call to its eventual result, whichever engine ran it.

Polling for results

POST /orchestration/poll
Authorization: Basic <credentials>
Content-Type: application/json

{
  "name": "flowdrop_pipelines",
  "timestamp": 1234567890
}
[
  {
    "timestamp": 1234567890,
    "data": {
      "pipeline_id": "123",
      "workflow_id": "my_workflow",
      "trigger_config_id": "my_workflow__node_abc",
      "status": "completed",
      "started": 1234567880,
      "completed": 1234567890,
      "input_data": { },
      "output_data": { },
      "error_message": null
    }
  }
]

Three guarantees govern what a poll returns:

  • Every terminal run is reported — completed, failed and cancelled — so a caller always reaches an end state rather than waiting forever on a run that quietly stopped. A run that is still executing or paused appears once it finishes.
  • Only externally invoked runs are exposed. Scoping is on a positive source: orchestration marker, never on the presence of trigger_config_id — cron, entity and form triggers set that too, and scoping on it leaked unrelated internal runs, including their full output, to external callers.
  • One poll returns at most one page (50 runs). Poll again with the highest timestamp / id you received to collect the rest; a backlog drains over consecutive polls and nothing is skipped or repeated on the way.

The response is a page, not the whole backlog

The poll is incremental by design — you hand back the last cursor you saw — so the handlers never materialise more than a page of pipelines at a time, whatever the site's history. Two details make paging safe to rely on: a set of runs that finished in the same second is never split across a page boundary (a timestamp cursor could not express the split, so the tail would be lost), and a page that contains only internal runs is never answered as an empty result — the handler keeps reading until it has something for you or the backlog is genuinely empty. An empty response therefore means nothing new, always.

Configuration

Trigger conditions

Event-type-specific settings live under conditions.custom, which is the trigger system's declared extension point. Both keys are declarative metadata published to the calling platform — neither is enforced.

Key Purpose
payload_schema JSON Schema describing the expected input, so the platform can render typed fields.
required_fields Surfaced in discovery so the platform can mark fields required in its own form.

Orchestrator settings

The shared trigger orchestrator settings apply: type, pipeline mode (new / reuse / singleton), retry policy and timeout.

The in-memory orchestrator is not usable here

flowdrop_runtime:synchronous persists no pipeline entity, so its runs could never be polled. A trigger configured this way is logged and run on synchronous_pipeline instead.

What this module does not do

Not supported Who handles it instead
Webhook / push delivery The platform polls. Delivery semantics — timeouts, retry, dedup — are not an adapter's job, and polling reads persisted pipeline state, so it cannot stall a caller and survives changes to the execution engine.
Validating the payload Nothing is enforced. payload_schema and required_fields are declarative; a payload violating them is passed through unmodified for the workflow to deal with.
Nested payload schemas Only top-level properties become typed fields; deeper structure rides inside payload as an object.
The in-memory flowdrop_runtime:synchronous orchestrator See above — a trigger configured this way falls back to synchronous_pipeline.

Developer API

Services

Service ID Class Description
flowdrop_orchestration_connector.services_provider ServicesProvider Publishes FlowDrop workflows as callable orchestration services
flowdrop_orchestration_connector.invoke_trigger_service InvokeTriggerService Bridges Orchestration API calls to FlowDrop pipeline/job execution
flowdrop_orchestration_connector.poll_event_subscriber PollEventSubscriber Answers /orchestration/poll from persisted pipeline entities

Architecture

External Platform (Activepieces, n8n, …)
        │  POST /orchestration/service/execute
        ▼
  Orchestration Module API
        ▼
  ServicesProvider::execute()
        ▼
  InvokeTriggerService::invoke()
        │  builds the request via flowdrop_trigger's
        │  OrchestrationRequestBuilder — the same shared
        │  builder the cron, entity and form triggers use
        ▼
  FlowDrop pipeline / job system

Results flow back the other way, on the platform's schedule:

External Platform
        │  POST /orchestration/poll
        ▼
  PollEventSubscriber  →  reads persisted pipeline entities

The connector subscribes to no runtime execution events. A run with no pipeline entity is invisible externally.

Troubleshooting

Workflows not appearing in the service list

  • Ensure the workflow has an Orchestration Trigger node.
  • Check that both the trigger and the workflow are enabled.

Authentication failures (403 for every non-admin user)

  • Ensure basic_auth is enabled.
  • Otherwise this is almost certainly the upstream permission bug described under Installation. Confirm by repeating the request as user 1.

No results coming back

  • Results are pulled, not pushed. Poll /orchestration/poll; this module registers no webhooks.
  • Only runs backed by a pipeline entity are visible — the in-memory synchronous orchestrator persists nothing.
  • Only terminal runs are returned. A paused run appears once it resolves or is cancelled.

References