How it works

Four pictures cover the whole runtime: where Junctree sits, what a run looks like, how configuration is resolved per tenant, and how versions move to production.

1 · Where Junctree fits

Junctree sits between your application and the third-party APIs you depend on. Instead of spreading vendor SDKs, credentials, and retry logic across your codebase, your app makes one typed call and Junctree handles the rest. Webhooks and schedules can drive the same junctions.

flowchart LR subgraph Stack["Your stack"] YourApp["Your application"] YourDB[("Your data")] end subgraph Ext["External inputs"] Hooks["Vendor webhooks"] Sched["Scheduled jobs"] end Junctree["Junctree<br/>versioned · typed · multi-tenant<br/>owns credentials, contracts, retries"] subgraph APIs["Third-party APIs"] Stripe["Stripe"] FX["FX rates"] Auth["Auth providers"] end YourApp -->|one typed call| Junctree Hooks --> Junctree Sched --> Junctree Junctree --> Stripe Junctree --> FX Junctree --> Auth

2 · The anatomy of a run

A run starts when your app calls /api/v1/execute, a webhook arrives, or a schedule fires. The runtime resolves the junction, picks the version that is live, and checks the caller is allowed. Then it runs the trigger's steps in order — each step's output flows into the next, and configuration and secrets are injected automatically, so the caller never handles a credential.

flowchart LR subgraph In["Where a run starts"] App["Your app calls /execute"] Hook["A webhook arrives"] Cron["A schedule fires"] end subgraph RT["Junctree runtime"] Resolve["Resolve the junction<br/>pick the live version<br/>check the caller is allowed"] Run["Run steps in order<br/>each output feeds the next<br/>config + secrets injected"] end subgraph Out["What it reaches"] Vendor["Third-party APIs"] Sub["Other junctions"] end App --> Resolve Hook --> Resolve Cron --> Resolve Resolve --> Run Run --> Vendor Run --> Sub Run --> Result["Result to the caller"]

3 · Multi-tenant cascade

The same junction can behave differently per tenant without being forked. At execution time the runtime walks the principal lineage from the platform root down to the caller, merging configuration and decrypting secrets as it goes. Lower tiers override higher ones, so a sub-account's setting beats its organization's, which beats the platform default.

flowchart TB subgraph Lineage["Principal lineage · root first"] direction TB A["admin<br/>platform defaults"] O["org<br/>customer overrides"] S["sub_account<br/>finer overrides · optional"] A --> O --> S end S --> Merge["Merge top-down<br/>lower tiers win"] Merge --> Ctx["config + secrets<br/>injected into the run"]

4 · Versions & lifecycle

Every junction has many immutable versions, but only one is published at a time. A version is editable while it is a draft; promoting it to testing freezes it for staging, and promoting to published makes it live. Promotion is atomic and the previous published version is retired automatically — so rolling forward or back never leaves an in-between state.

flowchart LR D(["draft<br/>editable"]) T(["testing<br/>frozen · staging"]) P(["published<br/>production"]) R(["retired<br/>audit only"]) D -->|promote| T T -->|promote| P P -.->|a newer version publishes| R

Ready to call one? Head to the quickstart.