Headless routing engine · Go

Route anything.
Exactly once.

Send any signal — a lead, an AI task, a ticket, an event. Ductor scores it, assigns it, and triggers the right workflow across 800+ connectors. Headless and durable, with no silent failures.

validateenrichfilterscore0assigntriggerexactly-once · syncSalesforceSlackHubSpotAnthropicOpenAIZendeskPagerDutyStripeKafkaWebhook
engine online
Routes: leads · AI · tickets · eventsDecides: scored & assignedTriggers: sync or asyncConnectors: 800+

Headless

Declare the route. We run it.

Match with CEL, score with a strategy, assign, then trigger a workflow — approvals, AI agents, connector actions — sync or in the background. Write it in Go, or declare it in YAML and ship with GitOps.

go get github.com/ductor/ductor
route.go
engine := ductor.New(store, queue)
 
// score and pick the destination with a pluggable strategy
engine.Strategy("weighted", strategy.Weighted())
 
// match anything with CEL, score a pool, then run a workflow
engine.Route(ductor.Route{
Match: `routable.type == "lead" && attrs.tier == "enterprise"`,
Strategy: "weighted",
Pool: "ae-west",
Then: ductor.Workflow{
Mode: ductor.Async, // or ductor.Sync — the caller waits
Steps: ductor.Steps{
ductor.Approval("sales-lead"), // human-in-the-loop
ductor.Connector("salesforce", "create_opportunity"),
ductor.Connector("slack", "notify"),
},
},
})
 
// durable, observable, exactly-once
decision, err := engine.Dispatch(ctx, routable)

How it works

A decision you can see.

Route anything

One generic Routable — a lead, an AI task, a support ticket, a webhook event — runs the same pipeline. The cargo changes; the machine doesn’t.

Decide, don’t guess

Filter with CEL rules, then score and select with a pluggable strategy: weighted round-robin, consistent-hash, least-loaded, priority, or a learning bandit.

Trigger workflows

Assignment kicks off a sync or async workflow — human approvals, event waits, subworkflows, AI agents — durable and exactly-once on a Postgres event log.

Strategies

How it decides is yours.

Selection is the intelligence of a route. Pick a strategy per pool — from round-robin to online learning bandits — or register your own.

Balance load

Spread work evenly across a pool.

weighted (SWRR)power-of-twoleast-loadedfair-catchuprandom-weighted

Score & route

Pick by rank, key, or fallback.

priority-scoreconsistent-hashfailover

Learn online

Adapt to live outcomes — bandits.

shark-tankthompson-samplinglinucbpredicted-value

By geography

Route on distance and region.

geo-nearestgeo-weighted

14 built-in strategies · implement Strategy for your own

Connectors

861 connectors. Both ends.

Triggers and destinations. Start a route from a webhook, a poll, a schedule, an event, or a direct API call — finish it with any action. Credentials are AEAD-encrypted: usable, never readable.

TriggersWebhookPollingScheduleEventAPISDK
Salesforce
HubSpot
Slack
Stripe
Twilio
Zendesk
OpenAI
Anthropic
Freshdesk
Pipedrive
SendGrid
Segment
PagerDuty
Kafka
Shopify
Jira
Mailchimp
Klaviyo
Intercom
Discord
Notion
QuickBooks
Square
Brevo

Routing that can’t lie to you.

No silent drops. No double-sends. Every route either lands or fails where you can see it.