---
title: "Re-apply a managed connection's desired records (async one-click, no re-consent)"
method: POST
path: "/connections/{id}:reapply"
tags: ["Connections"]
---

# Re-apply a managed connection's desired records (async one-click, no re-consent)

`POST /connections/{id}:reapply`

## Request

- Base URL: `https://api.customdomain.ai/v1`
- URL: `https://api.customdomain.ai/v1/connections/{id}:reapply`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.customdomain.ai/oauth/agent/authorize`, token URL `https://api.customdomain.ai/oauth/agent/token`, scopes: `domains:connect`)

**Managed mode only.** Recomputes the connection's authoritative desired record set and writes any drift through the provider's async one-click API using the stored, encrypted grant (the provider API base pinned at onboarding), or, for a connection managed through a provider sign-in, through the provider's DNS API with the kept credential (a refresh token is rotated first when the access token has expired); the end user does **not** re-consent. On success the connection is re-verified and `connection.records.updated` is emitted. A failure emits `connection.reapply.failed`; if the provider reports the grant was revoked (401 kill-switch, or a refused refresh token) the grant is cleared and the connection is flagged for re-consent (a sign-in grant leaves `error_code` `oauth_reconnect_needed`).

A domain kept by a continuous provider account (and no kept grant) is re-applied with the account's key: the records CustomDomain™ wrote for the domain are written back and the receipt says `via: provider_account`. A domain whose records CustomDomain™ did not write is refused with `409`, since re-applying would write records nobody put there. The same webhooks are sent.

A delegated agent token needs `domains:connect`.

## Path parameters

- `id` string, required

## Response `200`

Re-applied (records updated). NOTE: this is a re-apply RECEIPT, not a connection object; it carries `connection_id` rather than the connection's own `id`, and none of the other connection fields. Fetch `GET /connections/{id}` if you need the connection itself.

- ReapplyResult: The receipt returned by `POST /connections/{id}:reapply`. It is deliberately NOT a `Connection`: the re-apply endpoint reports the outcome of the provider write and the record set that was written, and carries no other connection state.
  - `connection_id` string, required: The connection the re-apply ran against (the `{id}` path parameter).
  - `reapplied` boolean, required: Always `true` on a `200`: the provider accepted the write for every template in the grant's bundle. Failures are reported as `409` (not managed / grant revoked), `422` (a provider account's key or write refused), `503` (managed rail unavailable) or `500`, never as `reapplied: false`.
  - `via` 'provider_account': `provider_account` when a continuous provider account's key wrote the records; omitted for a kept grant or a zone CustomDomain™ hosts.
  - `records` DnsRecord[], required: The authoritative desired record set as recomputed and written: the materialized template records for a template bundle, the records CustomDomain™ wrote for a provider account, otherwise the connection's default desired set.
    - `type` string, required: DNS record type. `APEXCNAME` is the engine's provider-agnostic CNAME-at-the-apex type (a plain CNAME is illegal at a zone apex); it is realized to the host's native ALIAS / ANAME / flattened-CNAME on write, and shown to users as `ALIAS` in manual instructions.
    - `host` string, required: fully-qualified record name
    - `value` string, required
    - `ttl` integer
    - `priority` integer, nullable: MX only
    - `applied` boolean: true once written through a provider
    - `change` 'created' | 'added' | 'replaced' | 'merged' | 'existing': What writing this record did to its name, recorded when we wrote it through a provider API. `created`: nothing of this type was there. `added`: our value joined a shared TXT or CAA set and the values already there were kept. `replaced`: the values of this type at the name were replaced (`prior` holds them). `merged`: an SPF policy was merged with the one already there (`prior` holds the original). `existing`: our exact value was already there, so removing the domain leaves it. Omitted when not recorded (a manual or one-click setup, or a record written before this was recorded).
    - `prior` PriorValue[]: The values this record replaced, so removing the domain can put them back. Omitted when nothing was replaced or it is unknown.
      - `type` string, required
      - `value` string, required
      - `ttl` integer
      - `priority` integer
    - `prior_source` 'provider' | 'public_dns': Where `prior` was read: `provider` (through the provider's API right before the write) or `public_dns` (observed in public DNS before the change). Omitted when unknown.

## Other responses

- `400`: Error envelope: {code, title, details}.
- `401`: Error envelope: {code, title, details}.
- `403`: Error envelope: {code, title, details}.
- `404`: Error envelope: {code, title, details}.
- `409`: The connection is not managed, has no stored grant, or the grant was revoked (re-consent required); or a provider account keeps it and CustomDomain™ did not write its records, or the account holds no usable key
- `422`: The provider refused the provider account's key (`ProviderAuthenticationError`) or the write (`dns_write_failed`)
- `503`: Error envelope: {code, title, details}.

---

[API](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api.md) · [All operations](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/llms.txt) · [OpenAPI document](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/revisions/34d89cb7a7cd?raw)
