---
title: "Read-only SPCS writeback-readiness signal (no side effects)."
method: GET
path: "/v1/connections/host/writeback-readiness"
tags: ["connections"]
---

# Read-only SPCS writeback-readiness signal (no side effects).

`GET /v1/connections/host/writeback-readiness`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/connections/host/writeback-readiness`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

Snowflake mode only (DVT-2905 r3 review fix, HIGH-1). The READ-ONLY companion
to `POST /v1/connections/host/test`'s `writeback` field: that route runs four
caller's-rights checks AND mutates shared state on every call (stamps
`lastTestedAt`/`lastTestError` onto the org-shared host connection row,
writes a `connection.test` audit row, and can flip `/admin/health`'s
needs-attention surface) — a page-mount effect that only wants the
writeback-readiness signal must not pay that side effect just to render.

This route calls the SAME engine-side readiness plumbing
(`POST /internal/writeback/readiness`) but skips the four caller's-rights
checks entirely and never touches `RecordConnectionTest` or the audit log.
It always requests the engine's cached-first behavior (`fresh: false`) —
honoring the engine's per-process provisioned-cache memo rather than paying
for a live Snowflake connection on every page load; the explicit "Verify
setup" button in the admin panel still goes through
`POST /v1/connections/host/test` (`fresh: true`) for a live diagnostic.

Any authenticated member holding `data:query` may call it — same scope gate
as `POST /v1/connections/host/test`. Off snowflake mode, this route does not
exist (`404`, leak-safe).

## Response `200`

The writeback-readiness signal, or omitted when no signal is available.

- object
  - `data` HostWritebackReadinessResult, required: Response body for GET /v1/connections/host/writeback-readiness (DVT-2905 r3 review fix, HIGH-1) — the read-only companion to HostConnectionTestResult's own writeback field. See that route's own description for how it differs from POST /v1/connections/host/test.
    - `writeback` WritebackReadiness: SPCS writeback-readiness surface (DVT-2905 slice B, ADR-0077 r3; fresh semantics added in the r3 review round, HIGH-1), snowflake mode only — present on HostConnectionTestResult's writeback field (POST /v1/connections/host/test) and on GET /v1/connections/host/writeback-readiness's own writeback field, only when the org's boot-provisioned Host Snowflake Writeback connection resolves; omitted everywhere else (gallery/enterprise, or a snowflake deployment where writeback hasn't provisioned yet). Backed by a DESCRIBE-based probe run under app identity (never the caller's own token). POST /connections/host/test (the explicit "Verify setup" click) always requests a LIVE probe; GET /connections/host/writeback-readiness (a page-mount/background read) honors the engine's per-process provisioned-cache memo instead — a cache hit reports provisioned:true with an empty appDatabase (no connection was opened). Writeback needs TWO independent things from the consumer, and `provisioned` covers only the first. The warehouse* fields (DVT-2924) carry the second: whether the APPLICATION's own identity has compute. Binding the app's consumer_warehouse reference is necessary but NOT sufficient — it names a warehouse without granting the application usage of it, and the app-identity session holds no warehouse privilege of its own. A cache hit on the GET route reports these from a short-TTL memo (warehouse state, unlike provisioning, is not monotonic), so unlike appDatabase they are still populated there.
      - `provisioned` boolean, required: Whether the org's dvt_writeback database exists and is visible to the application's own identity. NOT a check that the app can CREATE SCHEMA or CREATE TABLE there: errno 3001 (visible but under-privileged) also reports true (DVT-5275); a missing CREATE SCHEMA grant surfaces later, at the first flush.
      - `appDatabase` string, required: The Snowflake APPLICATION database name for this deployment, for templating GRANT ... TO APPLICATION "<name>" statements in the admin panel. May be empty when a GET /connections/host/writeback-readiness cache hit skipped opening a connection — callers fall back to a placeholder in that case (see WritebackSetupPanel).
      - `writebackDatabase` string, required: This install's resolved Snowflake writeback database (DVT-5156) - the name the admin panel templates its GRANT statements against. Frozen once at API startup from WRITEBACK_SNOWFLAKE_DATABASE; always populated, including on a cache-hit GET.
      - `warehouseBound` boolean: Whether a warehouse NAME resolved into the application's own connection — i.e. the app's consumer_warehouse reference is bound (DVT-2924). False means the remediation is to bind the reference on the app's Privileges/Security page in Snowsight. OMITTED when the engine could not resolve the signal at all; an absent field means "unknown" and MUST NOT be read as false — telling an admin to bind a reference they already bound is the failure this field exists to prevent.
      - `warehouseUsable` boolean: Whether the application's OWN session actually has that warehouse active (CURRENT_WAREHOUSE() is non-null). warehouseBound:true with warehouseUsable:false means the reference is bound but the application was never granted usage of the warehouse, and the remediation is `GRANT USAGE ON WAREHOUSE <name> TO APPLICATION "<app>"` — NOT re-binding. Both states produce the identical user-visible symptom (Snowflake errno 606 on every writeback DML, with rows queueing silently), which is why they are reported separately. Omitted under the same conditions as warehouseBound, with the same absent-means-unknown rule.
      - `warehouseName` string: The warehouse identifier to template the GRANT statement against — the effective (session) name when usable, else the requested one. OMITTED (not empty-string) when no warehouse is bound, and also when the name failed the identifier allowlist — callers fall back to a placeholder in both cases. Engine-side validated against the same allowlist as appDatabase before being returned; unlike appDatabase, a rejection degrades this field to omitted rather than failing the whole probe, so warehouseBound/warehouseUsable still report.
      - `flushHold` WritebackFlushHold: Present on WritebackReadiness ONLY while the stranded-sheet flush hold (DVT-5166) is in force: the install's writeback database was switched after one or more sheets were pinned to a previous database, so this process flushes nothing (new rows keep queueing in the WAL) until the install is switched back and restarted, or an admin acknowledges it (POST /v1/orgs/{orgId}/writeback/flush-hold/acknowledge, which releases it without a restart). Computed at boot from the sheets' own pinned targets; strandedSheets is refreshed by each acknowledge attempt. Held until the process restarts without a covering acknowledgement, or an admin acknowledges it. Attached only when the engine readiness probe succeeded: a failed probe omits the whole writeback field (it is not "not provisioned", DVT-2924).
        - `cause` 'writeback-switch-stranded', required
        - `strandedSheets` integer, required: Count of pinned Snowflake sheets still naming a writeback database other than the install's current one. 0 when the count could not be computed - see strandedCountUnknown.
        - `strandedCountUnknown` boolean: True when the stranded count itself could not be computed (the hold is then taken fail-closed), so strandedSheets is 0 only as a placeholder. Omitted when the count is known.

## Other responses

- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action.
- `404`: Resource does not exist.
- `429`: Per-actor API rate limit exceeded (SEC-2). All authenticated `/v1` routes apply a per-actor fixed-window default tier; selected compute-heavy routes (connection tests, column describe, data export) apply an additional tighter tier. Auth endpoints apply a per-IP tier. Problem type: `https://docs.dvt.dev/errors/rate-limited`. Wait for the `Retry-After` response header value (seconds) before retrying.

---

[API](https://skmtc.dev/dvt/apis/dvt-rest-api.md) · [All operations](https://skmtc.dev/dvt/apis/dvt-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dvt/apis/dvt-rest-api/revisions/00016f504165?raw)
