Skip to content
downpipes docs

Getting support without giving us access

Support for downpipes is built on a constraint the rest of the product already lives by. The vendor holds no Cloudflare token for your account, no dashboard seat, and no standing credential of any kind, so there is nothing on the vendor side that can reach into your account to look at a problem. Support works on evidence you hand out, not on access we hold.

That sounds like it would make support hard. In practice it makes the common case simpler than a screen-share: you download a redaction-safe diagnostics bundle from the console and attach it to your ticket, and that single file carries what support needs to read your situation. When a live ticket needs fresh evidence after that, the one escalation is a short, scoped credential that you mint and you revoke. There is no other inbound path, and there is never a standing one.

This page sets out that support model end to end: the premise, the default flow, the single escalation, and what “no vendor access” does and does not mean.

The premise: support without a credential we hold

The two easy answers a support team usually reaches for are a vendor-held Cloudflare token and a vendor seat in your dashboard. The product’s no-custody rule forbids both, and the support code is written around that absence rather than asking you to relax it for a ticket (engine/src/admin/support.ts).

So the question the design answers is: how does support get the evidence it needs when it holds nothing? The answer has two parts. By default, you hand evidence out as a file. When that is not enough during a live ticket, you mint a short-lived, read-only credential that lets support pull the same evidence a few times, then you revoke it. Both paths move evidence outward from your account under your control. Neither gives the vendor anything that outlasts the ticket.

Opening a ticket

Everything below assumes a ticket already exists. If you do not have one yet, email support@downpipes.io describing the problem; support opens a ticket and replies with a reference. That mailbox is the one support channel the product points you at, including from inside the console itself when a licence claim fails (console/src/screens/licence/claim-code.ts, console/src/lib/billing.ts). Support recognises a paid customer from the sender’s email address: a named contact, an allow-listed domain, the purchaser’s email domain, or the Cloudflare zone a console claimed the licence from. The order and the exclusions are in how support recognises a customer. Once you have a reference, attach the bundle from the flow below to your reply on that ticket.

The default flow: download a bundle, attach it to the ticket

The lowest-friction path needs no inbound vendor access at all. Any signed-in role that holds posture.read can open the console, download the support bundle, and attach it to the ticket. Every built-in role holds it. From engine 0.3.6, the engine writes a support-bundle-generated row to the audit log each time its admin API serves a bundle (serveSupportBundle, engine/src/admin/router-status.ts). The bundle is a redaction-safe aggregation of what support actually reads: the engine version and its release provenance, presence-only status, the preflight report, per-downpipe run-history rows with their coarse error vocabulary, notification delivery outcomes, the licence tier, and an estate rollup that support uses to check a volume-banded licence at intake (buildSupportBundle, engine/src/admin/support.ts).

What the bundle deliberately leaves out is the point. It never contains a key, a secret value, a record name beyond your own downpipe names, or your data. The console states this at the download button, so the redaction-safe property is visible where you act on it (renderSupportBundle, console/src/screens/settings/support.ts).

The bundle is also self-protecting in transit. The engine signs it with the same run signer it uses to sign every backup, so support can confirm the file came from your engine and was not altered on the way (signedSupportBundle, engine/src/admin/support.ts). When a vendor support key is configured, the bundle is additionally sealed to that key with the same hybrid encapsulation that protects an archive, so the file stays confidential through whatever ticket system carries it (sealedSupportBundle, engine/src/admin/support.ts). The console reports the seal and signature state: a pre-ceremony engine serves the bundle unsigned and says so, and with no vendor key configured it tells you to treat the file like any diagnostic attachment (vendorSealPresentation, console/src/screens/settings/support.ts).

The signature is over the bundle’s own contents, which is provenance, not full archive verification. It lets support confirm the file is from your engine and unmodified. It does not turn the file into proof that a backup is recoverable, which is a separate path described under recovery.

Sending a pack is also the only moment the protected-data figure of a volume-banded licence is checked against your real estate. Your estate count has a separate check, when you enter a claim code: the console sends that engine’s Cloudflare account id with the code, and the control plane refuses a claim beyond the band’s estate count. The engine itself never measures your estate against your tier; the rollup sits locally in your console and in the engine’s own licence API (GET /admin/licence) either way, and support only sees it inside a pack you chose to attach. The check itself is deterministic and never blocks a restore: a ticket about data loss, a restore, or a security concern is helped first regardless of what the numbers say, with any true-up handled afterwards, while a routine ticket from an over-band account gets a friendly note and an invitation to talk about the right plan before deeper work proceeds. For the full band definitions and this policy in detail, see licensing, editions, and the control-plane; for exactly what the estate rollup contains, see the support bundle.

The single escalation: a short, Owner-minted diagnostics pull

Sometimes a file attached at one moment is not enough, and support needs to pull fresh evidence while a ticket is live. That is the only case where evidence flows on the vendor’s request rather than yours, and even then you stay in control of it.

The mechanism is a platform-issued credential under the diagnostics scope. An Owner mints it, support presents it to fetch the same signed bundle once or a few times from a route that sits outside the admin API, and the Owner revokes it when the ticket is done (mintIngestCredential and handleSupportPull, engine/src/admin/support-ingest.ts). The credential grants exactly one read-only feed. It carries no admin route, no restore, no configuration write, and no access to your data (handleSupportPull, engine/src/admin/support-ingest.ts).

  1. An Owner mints the credential

    Minting is Owner-only, enforced server-side, and audited; a refused attempt is recorded the same way a refused role change is (POST /admin/support/credentials, engine/src/admin/router-status.ts). Because opening a pull surface carries the custody weight of granting a role, the mint is an opt-in dual-control action: when dual control is on, a second Owner approves the decision before the credential is issued.

    The mint also asks you to re-authenticate at the moment you make it: with your passkey, or with a fresh Cloudflare Access sign-in for an Access session. The step-up is one the engine requires on the route, rather than a console prompt you could skip. Dual control does not substitute for it. Dual control is opt-in and needs a second Owner, so it gives a single-Owner account nothing, and a stale browser session alone cannot open a read-only pull surface and hand back a bearer. The secret is shown once, behind a conceal and reveal field that copies without revealing. The console never stores it (oneTimeCredentialReveal, console/src/screens/settings/support.ts).

  2. Support pulls the bundle

    Support presents the credential as a single bearer token to fetch the sealed and signed bundle. The engine verifies it with a constant-time hash comparison against the stored hash and enforces expiry on its own clock, so a stale credential simply stops working (checkIngestCredential, engine/src/admin/support-ingest.ts). Every successful pull is recorded on the grant, and the console shows you when the credential was last used (supportGrantPresentation, console/src/screens/settings/support.ts).

  3. The Owner revokes it

    Revocation is immediate and Owner-only: confirm it and support stops working at once. It asks for no step-up, deliberately and unlike the mint: requiring a fresh re-authentication to shut off a credential you suspect is stolen would be friction at the worst moment. Re-minting issues a fresh credential and kills the old secret straight away, which is the rotation path. The fresh mint asks for the step-up the revoke did not (POST /admin/support/credentials/delete, engine/src/admin/router-status.ts).

The credential is short by design. It defaults to 72 hours and is capped at 7 days, so even an un-revoked credential ages out on the engine’s own clock well inside the life of a ticket (INGEST_TTL_CAPS_SECONDS, engine/src/admin/support-ingest.ts). Only the secret’s SHA-384 is ever stored, never the secret, so neither the engine nor the console can hand the live secret to anyone after the one-time reveal. For the credential lifecycle in full, see pull credentials.

Default versus escalation, side by side

The two paths differ in who initiates the evidence flow and in whether any inbound access exists at all.

Default flowEscalation
Who actsAny role with posture.read downloads the bundleAn Owner mints the credential; support pulls
Inbound vendor accessNone: you attach the file to the ticketOne read-only diagnostics pull, time-boxed and revocable
What support receivesThe redaction-safe bundle you choose to sendThe same bundle, fetched while the credential is valid
LifetimeThe single file you attachedDefault 72 hours, 7-day cap, or until you revoke
Control pointYou decide what to attach and whenYou mint it and you revoke it

In both rows the evidence is the same redaction-safe bundle. The only difference the escalation adds is a short window in which support may fetch it without waiting for you to re-attach a file. An Owner opens and closes that window.

What “no vendor access” means

“No vendor access” is a statement about custody, not about what is reachable on the network. The vendor holds no Cloudflare token, no dashboard seat, and no standing credential for your account. There is no credential sitting on the vendor side, by default or otherwise, that opens a door into your engine.

The Owner-minted diagnostics lease does not contradict that. A lease you create, scope to read-only, time-box, and revoke is consistent with no-custody because the vendor never holds it as a standing capability: it exists only while you allow it, grants only one read-only feed, and the engine refuses it the moment it expires or you revoke (checkIngestCredential and handleSupportPull, engine/src/admin/support-ingest.ts). The control sits with you at every step, which is the property no-custody is about. For the full account of what the vendor and the engine can and cannot hold, see the no-custody trust model.

The audit content carries operator identity, so it is not free of personal data. The audit feed records actor email, source address, role and approver identities. The bundle carries no operator email: it drops each one or reduces it to a yes-or-no flag. It does include your own downpipe names and operational facts. Treat neither file as anonymous telemetry. Only the bundle is sealed in transit, and only when a vendor key is configured.

The bundle’s integrity property is tamper-evident: the run signer’s signature lets support detect a file that was altered after your engine produced it. It does not stop the file being altered; it makes an alteration detectable.

Where this fits

Deeper detail: the routes, the audit feed, and what is not in the CLI

Three scopes, three lifetimes. The platform issues a client and secret credential per scope. The diagnostics scope is the short-lived support pull described above.

A separate audit-feed scope lets your own SIEM collector poll the hash-chained audit events on a long-lived schedule. The schedule defaults to 90 days and is capped at 365, cursored by sequence number for checkpointing. A third, metrics scope lets a Prometheus-compatible scraper pull the /metrics surface on the longest-lived schedule of the three. The schedule defaults to 365 days and is capped at 400 (INGEST_TTL_CAPS_SECONDS and handleSupportPull, engine/src/admin/support-ingest.ts; /metrics is served by handleMetricsRoute, engine/src/admin/metrics.ts, not by the /support/* pull route). One credential is active per scope; re-granting replaces it. The audit feed and the metrics feed are both customer-operated, not a vendor path; the audit feed is described under the audit log and the metrics feed under backup health for your monitoring stack.

The pull route sits outside the admin API. Support never authenticates as a console user. The diagnostics pull is served from a route that takes no admin token and no Access seat, gated only by the bearer credential for the matching scope; a failed presentation is a plain unauthorised response with no detail (handleSupportPull, engine/src/admin/support-ingest.ts). The most recent 50 pulls are retained on the grant for you to see, and older entries roll over, so the console reports recent usage rather than a total it cannot know (supportGrantPresentation, console/src/screens/settings/support.ts).

The Go reader’s bundle is a different artefact. The MIT-licensed offline reader has no support path, no ingest credential, and no offboarding capability. Where its documentation says “bundle” it means the in-bucket recovery bundle: a verbatim copy of the format specification and plain recovery instructions, plus a SHA384SUMS over them with a detached hybrid signature, which the reader can verify with its --check-bundle option. That recovery-notes bundle is not the encrypted archive itself and is unrelated to the support bundle this page describes; do not read one as the other.

For exactly what the downloaded file contains, field by field, see the support bundle. For the credential lifecycle, the dual-control gate and the usage trail, see pull credentials. When you are leaving the product, the controlled exit sequence (removing roles, deprovisioning identity in your own dashboard, and keeping your offline keys) lives in leave downpipes.

Last updated .