Self-hosting (BYOC)
Self-hosting (BYOC)
Use self-hosting to export a saved flow or agent as a self-contained
@runtypelabs/runtime definition. Run the definition on Cloudflare Workers,
Cloud Run, Node, Vercel Functions, or another environment with a runtime
adapter. The runtime calls Runtype for model execution through the platform-key
proxy and for hosted memory, crawl, email, search, and asset storage.
Self-hosting (BYOC, or bring your own cloud) requires an Enterprise plan. After you
authenticate with the required permission, your account receives HTTP 403 with the code
BYOC_PLAN_REQUIRED if it lacks an Enterprise plan. Contact support to enable self-hosting for
your account.
Export a flow or agent
The export endpoints return fully resolved definitions that the
@runtypelabs/runtime package consumes at startup. The flow export inlines step
configurations. The agent export inlines capabilities, flows, and nested
sub-agents through up to three levels, and replaces MCP credential values with
secret-name references.
To export a flow, send this GET request:
To export an agent, send this GET request:
Replace the placeholders in both requests as follows:
FLOW_ID: ID of the flow to export.AGENT_ID: ID of the agent to export.YOUR_API_KEY: Runtype API key with theRUNTIME:EXPORTscope.
On an account without an Enterprise plan, both endpoints return this response:
Host dependencies
Some things a flow or agent can do are not self-contained: the runtime hands
them to the host rather than performing them itself. An export is never refused
for containing one. Instead, both export responses carry hostDependencies —
the runtime seams you have to wire before the artifact can run everything it
describes:
ExecuteAgentOptions.onDurablePause is the agent-lane sibling of the first one,
with the same contract. The durable-pause dependency is satisfied by either
channel: wiring onDurablePause, or consuming the durable-paused
FlowStreamOutcome yourself (the executeFlowToWriter path, where a host that
already arms its own scheduler needs no hook).
The runtime does not ship a default implementation of either seam today. If you
wire neither channel, a run that reaches a durable step now fails with a
truthful terminal error — execution_error with the stable code
DURABLE_PAUSE_HOST_NOT_CONFIGURED — instead of reporting a paused success
nobody is holding. The runtime also offers a pre-flight helper you can call at
boot, so a missing dependency surfaces on startup with the full list rather than
mid-run at the first durable step. Defaults may ship later; an artifact that no
longer needs a seam simply stops declaring it.
hostDependencies is always present. An empty array means the artifact is
fully self-contained.
Each entry names the sites that caused it. The scan covers the artifact’s
entire executable closure, not just its own top-level steps: conditional
branches, embedded agents’ capabilities, and the flow or
sub-agent definitions carried inline by a runtime tool. A site therefore often
names a step that does not appear in the flow you exported, which is why every
one carries ownerKind (flow, agent, capability, or inline-tool) with
ownerId and ownerName where they exist.
Treat the list as open-ended: new kind values may appear, so render
interface and reason for a kind you do not recognise rather than failing.
The schema is built for that — an unrecognised kind deserializes as an entry
carrying just kind, interface, and reason, with any kind-specific evidence
alongside, so a client on an older SDK keeps working and can still tell you what
to wire.
Two things are worth separating from this. POST /v1/runtime/crawl below is a
synchronous crawl the hosted platform serves your runtime; it needs no
durable pause and is unrelated to the crawl flow step. And Workers for
Platforms artifacts are not self-hosted exports: Cloudflare Workflows cannot
live in a WfP dispatch namespace, and that host is ours rather than yours, so a
durable-class step makes an artifact permanently WfP-ineligible instead of
declaring a dependency you could wire.
Managed external-agent exports
An exported external agent with skillOrchestration: 'managed' is self-contained. At execution,
Runtime compiles the cached agent-card skills whose effective role is tool into ordinary A2A
runtime tools, then runs the configured skillOrchestrator model through the standard agent loop.
Surface/additional tools can be supplied through managedSkillOrchestration.additionalTools; no
hosted API orchestration engine is required.
External credentials are never embedded as plaintext. If the authored credential was already an
exact {{secret:NAME}} reference, the export preserves NAME. A hosted database credential is
exported as the agent-specific reference
{{secret:RUNTYPE_AGENT_EXTERNAL_AUTH_<AGENT_ID>}}. A self-hosted operator must provide that name
through the runtime platform adapter’s getSecret and resolveSecretReferences methods. The
hosted Runtype API recognizes the agent-specific name and resolves the sealed agent credential
automatically; a BYOC adapter must map it to the corresponding secret in its own secret store.
Execution timeouts
Set execution deadlines on each executeFlow or executeAgent call:
stepTimeoutMslimits one step attempt. An authored fallback retry receives a fresh attempt budget.flowTimeoutMslimits each virtual-flow, reflection, or final-reply turn. Each turn receives a fresh relative budget. For a delegated external agent, it limits the whole A2A call, including retries.wallClockTimeoutMsis the hard budget for the whole agent invocation. Every primary, reflection, and final-reply turn receives only the execution’s remaining time, and Runtime releases the caller even when a provider or tool promise ignores cancellation. Expiry during a primary turn fails the execution withAGENT_TURN_DEADLINE_EXCEEDED; expiry between completed turns remains a normalstopReason: 'timeout'loop stop. Delegated external agents apply the same hard cap to their A2A call. When it andflowTimeoutMsboth apply, the earlier finite deadline wins.
An external-agent input checkpoint persists flowTimeoutMs; the resumed peer turn receives a
fresh relative budget, so time spent waiting for human input is not charged. Hosted approval and
client-tool continuations likewise replay the original setting. Direct runtime callers can pass
Infinity to disable only flowTimeoutMs; hosted request schemas accept finite values only.
Hosted capability endpoints
The exported runtime uses these hosted endpoints for platform capabilities. The
Authenticate with a Runtype API key in the Authorization: Bearer header. The
API derives tenant identity from the authenticated API key, not from request
body fields.
The following table lists the hosted endpoint families and their capabilities:
When a hosted endpoint is available, it requires an Enterprise plan and
returns HTTP 403 with BYOC_PLAN_REQUIRED for an account without an
Enterprise plan. Use the API Reference for the full request and response
schemas.
POST /v1/runtime/crawl serves a synchronous crawl only. It is not a host
for the crawl flow step, which parks a durable pause and declares a
durable-pause-host dependency instead. See
Host dependencies.
Use an API key with FLOWS:EXECUTE or AGENTS:EXECUTE for memory and records
requests. Use an API key with FLOWS:EXECUTE for crawl, email, and search
requests. Use an API key with ASSETS:WRITE for POST /v1/runtime/assets.
Reporting telemetry
POST /v1/telemetry/ingest is separate from the hosted endpoint families. It
does not require an Enterprise plan. RuntimeConfig.telemetry posts to this
endpoint so the deployed runtime’s executions appear in the Runtype dashboard.
Use a separate API key with the TELEMETRY:WRITE scope. Create it with the
Telemetry Ingest permission group in the API-key dialog. Ingest is
append-only, so give this API key no other scopes.
The endpoint accepts any valid API key, and the API logs requests from keys
without the TELEMETRY:WRITE scope. Existing deployments continue to report
with their valid API keys.
Use a separate API key for the hosted endpoints. A shared API key also needs the execution scopes for those endpoints, which gives it more access than telemetry requires.
If you need to report on an agent that runs entirely outside Runtype, see Reporting telemetry from an external agent.
Redacting PII from telemetry
Telemetry payloads carry step output, tool results, and agent completions, so
they can contain end-user personal data. Set telemetry.piiRedaction to
'redact' to have Runtype mask detected PII (emails, phone numbers, and the
rest of the detector set) before it is stored:
An individual agent’s config.piiRedaction takes precedence over this
deployment-wide setting, in both directions: an agent exported with
piiRedaction: 'redact' is redacted even when the deployment sets nothing, and
an agent exported with piiRedaction: 'off' is not redacted even when the
deployment sets 'redact'. 'default' on an agent defers to the deployment
setting.
piiRedaction on an exported agent is a host-owned policy block, so declare it
handled on every executeAgent call that runs such an agent:
Without that declaration the runtime rejects an agent exported with piiRedaction: 'redact'
before it streams, throwing UnsupportedAgentConfigError whose unsupportedPaths names
config.piiRedaction. The deployment-wide telemetry.piiRedaction setting needs no declaration,
because it is not agent config.
The runtime resolves the policy per execution and sends it with each event, so one deployment can run redacted and unredacted agents side by side. Omitting both settings leaves redaction off, which is the existing behavior. Secret redaction is always applied and is not affected by this setting.
The public POST /v1/assets endpoint is separate from self-hosting and is available on every
plan. The runtime mount, POST /v1/runtime/assets, requires an Enterprise plan.
Firecrawl and Massive fetch methods
Standard HTTP requests in fetch-url steps run through the runtime adapter.
For Firecrawl or Massive, supply a ManagedFetchExecutor through
RuntimeConfig.managedFetchExecutor. The executor resolves credentials,
enforces provider policy, and sends the requests.
No hosted /v1/runtime/* endpoint handles managed fetch. If you omit
ManagedFetchExecutor, the default context-step executor returns a
not-supported error instead of calling the provider. If you supply a custom
contextStepExecutor, that executor handles the managed-fetch integration.
Embedding models beyond the built-ins
generate-embedding steps and the query embedding inside vector-search use
the runtime adapter for these OpenAI and Google model IDs:
text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002,
text-embedding-004, and gemini-embedding-001. The adapter resolves
OPENAI_API_KEY or GOOGLE_API_KEY for these models.
For any other embedding model ID, supply an EmbeddingProvider through
RuntimeConfig.embeddingProvider. This includes Weaviate vectorizer IDs such
as text2vec-openai, text2vec-cohere, text2vec-huggingface, and the
Snowflake/snowflake-arctic-embed-* family. Your Weaviate instance produces
these vectors, so the export does not include their credentials or
configuration.
No hosted /v1/runtime/* endpoint handles embedding. If you omit an
EmbeddingProvider, the affected steps fail with
EmbeddingProviderNotConfiguredError and name the model. They do not fall
back to another model. Built-in models continue to use their native provider
when you configure an EmbeddingProvider.
For tests and offline runs, use StaticEmbeddingProvider. It is not a real
embedder. It returns a vector derived from a hash of the input text.
Inspect each step’s embeddingModel before deployment. A flow can use a built-in model in one
step and require an EmbeddingProvider in another.
Record storage and tenancy scoping
The record steps, including upsert-record, get-record, list-records, and
update-record, use RuntimeConfig.recordStore. The runtime includes
InMemoryRecordStore for stateless agents and tests, and HostedRecordStore
for the hosted POST /v1/runtime/records/* endpoints. The default
NoOpRecordStore raises an error when a record step runs.
If an exported flow or agent includes tenancyStrategy, provide both of these
components:
- A scope-capable store: Set
supportsRecordScope = trueon yourRecordStoreimplementation. Honor thescopedescriptor on every call. Filter every read, including theupdate-recordtarget lookup. Add the scope columns on insert. Partition upsert conflict resolution by scope so the same(type, name)can exist for two tenants. - A resolved scope per execution: Resolve tenant and end-user identity in
your host. Pass the result as
ExecuteAgentOptions.recordScopewhen you callexecuteAgent. Pass it asExecuteFlowOptions.recordScopewhen you callexecuteFlowfor a standalone flow export.
An agent execution passes its scope to the flows that it runs. A top-level
executeFlow call does not infer the scope, so pass recordScope explicitly.
The export does not include Runtype identity resolution. Add
tenancyStrategy to handledAgentConfig before the runtime accepts the agent.
If an execution carries a resolved scope but the store does not declare support for it, the record
step fails with RecordScopeUnsupportedError. The step does not read or write the global
namespace. HostedRecordStore does not declare record-scope support because the hosted API does
not accept a scope descriptor, so the server cannot verify the execution’s tenant.
If you omit tenancyStrategy, the runtime uses the plain owner namespace.
Collection schema validation
If you register a record type as a collection with a metadata schema, the
upsert-record and update-record steps call
RuntimeConfig.collectionValidator before each write. upsert-record merges
on conflict inside the store, so validation checks the incoming payload for
each batch item. update-record reads the target row first, so validation
checks the post-merge metadata.
The validator exposes two methods:
validate(type, metadata): Returns the verdict for writingmetadataas a record oftype. It does not throw. A lookup failure returnsunevaluated.prime(type): Warms the collection lookup without validating data. Call it before validation inside an open transaction. A cold lookup in that transaction can deadlock a single-session driver.
With an enforce verdict, the step rejects the write. The step’s
errorHandling setting controls the failure, as it does for a payload-limit
violation. With a warn verdict, the step writes and adds schemaWarnings to
the step metadata. The upsert-record batch path does not report warnings.
The verdict is stored in the schemaValid write field. A store that persists
that field records the same validation result as Runtype. For validation modes
and violation details, see Defining a schema.
No hosted /v1/runtime/* endpoint handles collection validation. The hosted
record endpoints do not evaluate collection schemas. If your self-hosted
deployment needs enforcement, supply a validator backed by your collection
definitions.
If you omit the validator, every verdict is unevaluated. Writes proceed without a schemaValid
stamp. This behavior is intentional because validation is an owner-configured contract for
metadata shape, not a security boundary. A collection set to enforce in the dashboard is not
enforced by an exported flow or agent until you wire a validator.
Next steps
Continue with these guides:
- Runtime tools: define tools inline with dispatch requests
- API Reference: inspect full request and response schemas