technitium 0.4.0

Typed async Rust client for the Technitium DNS Server API
Documentation
# Update Record

## Endpoint

`/api/zones/records/update`

## Method

GET (query parameters)

## Description

Updates an existing record in an authoritative zone. For most record types, both the current value (to identify the record) and the new value must be provided. If the "new" parameter is omitted, the current value is retained.

## Authentication

Required. Session token from `login` or `createToken`.

## Permissions

- Zones: None
- Zone: Modify

## Common Parameters

| Name | Type | Required | Conditional | Description |
|------|------|----------|-------------|-------------|
| `token` | string | Yes | No | Session token from `login` or `createToken` |
| `domain` | string | Yes | No | The domain name of the zone to update the record |
| `zone` | string | No | No | The authoritative zone name. When unspecified, the closest authoritative zone is used |
| `node` | string | No | No | Node domain name for clustering. Only usable when Clustering is initialized |
| `type` | string | Yes | No | The resource record type to update |
| `newDomain` | string | No | No | New domain name for the record (used to rename the subdomain) |
| `ttl` | integer | No | No | TTL value in seconds. Default: `3600` when missing |
| `disable` | boolean | No | No | Whether to disable the record. Default: `false` |
| `comments` | string | No | No | Comments for the resource record |
| `expiryTtl` | integer | No | No | Auto-delete the record after this many seconds since last modified time |

## Per-Record-Type Parameters

Update operations use a **current/new value pattern**: current values identify the record to update; new values specify what to change it to. If "new" values are omitted, current values are retained.

### A / AAAA

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `ipAddress` | string | Yes | Current IP address (identifies the record) |
| `newIpAddress` | string | No | New IP address. Uses current value when missing |
| `ptr` | boolean | No | When `true`, also update the associated PTR record |
| `createPtrZone` | boolean | No | When `true`, create the reverse zone for PTR if needed |
| `updateSvcbHints` | boolean | No | When `true`, update SVCB/HTTPS records with Automatic Hints matching this domain |

### NS

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `nameServer` | string | Yes | Current name server domain name (identifies the record) |
| `newNameServer` | string | No | New name server domain name. Uses current value when missing |
| `glue` | string | No | Comma-separated list of glue IP addresses |

### CNAME

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `cname` | string | Yes | The new CNAME domain name to set |

**Note:** CNAME has no current/new pattern because only one CNAME record can exist per domain name.

### SOA

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `primaryNameServer` | string | Yes | Primary name server |
| `responsiblePerson` | string | Yes | Responsible person email |
| `serial` | integer | Yes | SOA serial number |
| `refresh` | integer | Yes | Refresh interval in seconds |
| `retry` | integer | Yes | Retry interval in seconds |
| `expire` | integer | Yes | Expire time in seconds |
| `minimum` | integer | Yes | Minimum TTL in seconds |
| `useSerialDateScheme` | boolean | Yes | Enable date-based serial numbering. Only for `Primary`, `Forwarder`, and `Catalog` zones. Default: `false` |

**Note:** SOA has no current/new pattern because only one SOA record exists per zone.

### PTR

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `ptrName` | string | Yes | Current PTR domain name (identifies the record) |
| `newPtrName` | string | Yes | New PTR domain name |

**Note:** The docs mark `newPtrName` as required (not optional-defaults-to-current like most other types).

### MX

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `preference` | integer | No | Current preference value. Defaults to `1` when missing |
| `newPreference` | integer | No | New preference value. Uses old value when missing |
| `exchange` | string | Yes | Current exchange domain name (identifies the record) |
| `newExchange` | string | Yes | New exchange domain name |

**Note:** The docs mark `newExchange` as required.

### TXT

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `text` | string | Yes | Current text value (identifies the record) |
| `newText` | string | Yes | New text value |
| `splitText` | boolean | No | Current split text value. Default: `false` |
| `newSplitText` | boolean | No | New split text value. Uses current when missing |

**Note:** The docs mark `newText` as required.

### RP

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `mailbox` | string | Yes | Current email address (identifies the record) |
| `newMailbox` | string | No | New email address. Uses current value when missing |
| `txtDomain` | string | Yes | Current TXT domain name (identifies the record) |
| `newTxtDomain` | string | No | New TXT domain name. Uses current value when missing |

### SRV

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `priority` | integer | Yes | Current priority (identifies the record) |
| `newPriority` | integer | No | New priority. Uses old value when missing |
| `weight` | integer | Yes | Current weight (identifies the record) |
| `newWeight` | integer | No | New weight. Uses old value when missing |
| `port` | integer | Yes | Current port (identifies the record) |
| `newPort` | integer | No | New port. Uses old value when missing |
| `target` | string | Yes | Current target (identifies the record) |
| `newTarget` | string | No | New target. Uses old value when missing |

### NAPTR

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `naptrOrder` | integer | Yes | Current order value (identifies the record) |
| `naptrNewOrder` | integer | No | New order value. Uses old value when missing |
| `naptrPreference` | integer | Yes | Current preference (identifies the record) |
| `naptrNewPreference` | integer | No | New preference. Uses old value when missing |
| `naptrFlags` | string | Yes | Current flags (identifies the record) |
| `naptrNewFlags` | string | No | New flags. Uses old value when missing |
| `naptrServices` | string | Yes | Current services (identifies the record) |
| `naptrNewServices` | string | No | New services. Uses old value when missing |
| `naptrRegexp` | string | Yes | Current regexp (identifies the record) |
| `naptrNewRegexp` | string | No | New regexp. Uses old value when missing |
| `naptrReplacement` | string | Yes | Current replacement (identifies the record) |
| `naptrNewReplacement` | string | No | New replacement. Uses old value when missing |

**Note:** NAPTR uses `naptrNewOrder` (not `newNaptrOrder`) -- inconsistent naming with other types. All "new" params for NAPTR are prefixed `naptrNew*`.

### DNAME

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dname` | string | Yes | The new DNAME domain name |

**Note:** DNAME has no current/new pattern because only one DNAME record can exist per domain name.

### DS

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `keyTag` | integer | Yes | Current key tag (identifies the record) |
| `newKeyTag` | integer | Yes | New key tag |
| `algorithm` | string | Yes | Current algorithm (identifies the record) |
| `newAlgorithm` | string | Yes | New algorithm |
| `digestType` | string | Yes | Current digest type (identifies the record) |
| `newDigestType` | string | Yes | New digest type |
| `digest` | string | Yes | Current digest (identifies the record) |
| `newDigest` | string | Yes | New digest |

**Note:** All "new" DS fields are marked as required (no default-to-current behavior).

### SSHFP

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `sshfpAlgorithm` | string | Yes | Current algorithm (identifies the record) |
| `newSshfpAlgorithm` | string | Yes | New algorithm |
| `sshfpFingerprintType` | string | Yes | Current fingerprint type (identifies the record) |
| `newSshfpFingerprintType` | string | Yes | New fingerprint type |
| `sshfpFingerprint` | string | Yes | Current fingerprint (identifies the record) |
| `newSshfpFingerprint` | string | Yes | New fingerprint |

**Note:** All "new" SSHFP fields are marked as required.

### TLSA

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `tlsaCertificateUsage` | string | Yes | Current certificate usage (identifies the record) |
| `newTlsaCertificateUsage` | string | Yes | New certificate usage |
| `tlsaSelector` | string | Yes | Current selector (identifies the record) |
| `newTlsaSelector` | string | Yes | New selector |
| `tlsaMatchingType` | string | Yes | Current matching type (identifies the record) |
| `newTlsaMatchingType` | string | Yes | New matching type |
| `tlsaCertificateAssociationData` | string | Yes | Current certificate association data (identifies the record) |
| `newTlsaCertificateAssociationData` | string | Yes | New certificate association data |

**Note:** All "new" TLSA fields are marked as required.

### SVCB / HTTPS

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `svcPriority` | integer | Yes | Current priority (identifies the record) |
| `newSvcPriority` | integer | No | New priority. Uses old value when missing |
| `svcTargetName` | string | Yes | Current target name (identifies the record) |
| `newSvcTargetName` | string | No | New target name. Uses old value when missing |
| `svcParams` | string | Yes | Current service params (identifies the record). Pipe-separated key-value list |
| `newSvcParams` | string | No | New service params. Set to `false` to clear. Uses old value when missing |
| `autoIpv4Hint` | boolean | No | Enable Automatic Hints for `ipv4hint` in `newSvcParams` |
| `autoIpv6Hint` | boolean | No | Enable Automatic Hints for `ipv6hint` in `newSvcParams` |

### URI

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uriPriority` | integer | Yes | Current priority (identifies the record) |
| `newUriPriority` | integer | No | New priority. Uses old value when missing |
| `uriWeight` | integer | Yes | Current weight (identifies the record) |
| `newUriWeight` | integer | No | New weight. Uses old value when missing |
| `uri` | string | Yes | Current URI (identifies the record) |
| `newUri` | string | No | New URI. Uses old value when missing |

### CAA

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `flags` | integer | Yes | Current flags (identifies the record) |
| `newFlags` | integer | No | New flags value |
| `tag` | string | Yes | Current tag (identifies the record) |
| `newTag` | string | No | New tag value |
| `value` | string | Yes | Current value (identifies the record) |
| `newValue` | string | Yes | New value |

**Note:** The docs mark `newValue` as required for CAA.

### ANAME

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `aname` | string | Yes | Current ANAME domain name (identifies the record) |
| `newAName` | string | Yes | New ANAME domain name |

**Note:** Both current and new are marked as required.

### FWD (Forwarder - proprietary)

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `protocol` | string | No | Current protocol. Default: `Udp`. Valid: `Udp`, `Tcp`, `Tls`, `Https`, `Quic` |
| `newProtocol` | string | No | New protocol. Default: `Udp` |
| `forwarder` | string | Yes | Current forwarder address (identifies the record) |
| `newForwarder` | string | Yes | New forwarder address |
| `forwarderPriority` | integer | No | Current forwarder priority. Default: `0` |
| `dnssecValidation` | boolean | No | DNSSEC validation. Default: `false` |
| `proxyType` | string | No | Valid: `NoProxy`, `DefaultProxy`, `Http`, `Socks5`. Default: `DefaultProxy` |
| `proxyAddress` | string | No | Proxy address (when `proxyType` is configured) |
| `proxyPort` | integer | No | Proxy port (when `proxyType` is configured) |
| `proxyUsername` | string | No | Proxy username (when `proxyType` is configured) |
| `proxyPassword` | string | No | Proxy password (when `proxyType` is configured) |

**Note:** `newForwarder` is marked as required. `forwarderPriority` does not have a `newForwarderPriority` -- the same parameter sets the new value.

### APP (DNS App - proprietary)

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `appName` | string | Yes | DNS app name |
| `classPath` | string | Yes | Class path |
| `recordData` | string | No | App-specific record data |

**Note:** APP has no current/new pattern because only one APP record can exist per domain name.

### Unknown Record Types

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `rdata` | string | Yes | Current hex-encoded record data (identifies the record) |
| `newRData` | string | Yes | New hex-encoded record data |

## Response Fields

| Field | Type | Description |
|-------|------|-------------|
| `status` | string | `"ok"` on success |
| `response.zone.name` | string | Zone name |
| `response.zone.type` | string | Zone type |
| `response.zone.internal` | boolean | Whether the zone is internal |
| `response.zone.dnssecStatus` | string | DNSSEC signing status |
| `response.zone.disabled` | boolean | Whether the zone is disabled |
| `response.updatedRecord.disabled` | boolean | Whether the record is disabled |
| `response.updatedRecord.name` | string | Record domain name |
| `response.updatedRecord.type` | string | Record type |
| `response.updatedRecord.ttl` | integer | TTL in seconds |
| `response.updatedRecord.rData` | object | Record-type-specific data |
| `response.updatedRecord.dnssecStatus` | string | DNSSEC status |
| `response.updatedRecord.lastUsedOn` | string | Timestamp of last use |

## Conditional Logic Notes

1. **Current values are used to IDENTIFY which record to update.** Since multiple records of the same type can exist (e.g., multiple A records), the current value parameters act as a composite key to select the correct record.
2. **`ipAddress` is required when `type` is `A` or `AAAA`** to identify the record. `newIpAddress` is optional and defaults to the current value.
3. **`nameServer` is required when `type` is `NS`** to identify the record.
4. **For `CNAME`, `DNAME`, and `SOA`**: only one record of each type can exist per domain/zone, so there is no current/new identification pattern. You just provide the new values directly.
5. **All seven SOA fields are required** when updating SOA. `useSerialDateScheme` is also required and only applies to `Primary`, `Forwarder`, and `Catalog` zone types.
6. **For `PTR`**: both `ptrName` and `newPtrName` are required.
7. **For `MX`**: `exchange` and `newExchange` are required. `preference` defaults to `1` when missing.
8. **For `TXT`**: `text` and `newText` are required. `splitText` defaults to `false`.
9. **For `SRV`**: all four current fields are required for identification. All "new" fields default to old values.
10. **NAPTR uses inconsistent naming**: "new" params are `naptrNew*` (e.g., `naptrNewOrder`) not `newNaptr*`. All six current fields are required.
11. **For DS, SSHFP, TLSA**: ALL "new" fields are required (no default-to-current behavior). This is stricter than most other types.
12. **For SVCB/HTTPS**: `svcParams` uses pipe-separated format. `autoIpv4Hint` and `autoIpv6Hint` apply to the `newSvcParams`, not the current params.
13. **For FWD**: `protocol` defaults to `Udp`. `forwarderPriority` defaults to `0`. Proxy fields are only relevant when `proxyType` is `Http` or `Socks5`.
14. **`newDomain`** can be used with ANY record type to rename the subdomain portion of the record.
15. **`disable=true`** can be used with any record type to disable it without deleting.
16. **`ttl` defaults to 3600** when missing, which means omitting it during update will reset the TTL to 3600 even if the original was different.

## Edge Cases

- **TTL gotcha**: Unlike most "new" parameters that default to the current value, `ttl` defaults to `3600` when missing. This means an update that omits `ttl` will silently change the TTL to 3600.
- **NAPTR naming inconsistency**: The "new" parameter names for NAPTR break the `new{FieldName}` convention used by all other types. They use `naptrNew{FieldName}` instead (e.g., `naptrNewOrder` not `newNaptrOrder`).
- **DS/SSHFP/TLSA strictness**: These types require all "new" fields even if you only want to change one field. You must re-supply all values.
- **CNAME/DNAME/SOA/APP singularity**: These types can only have one record per domain, so the update doesn't need current-value identification.
- **FWD `forwarderPriority`**: There is no `newForwarderPriority` parameter. The `forwarderPriority` parameter serves as both the identifier and the new value, which is ambiguous. The current priority is used for identification and the same value is set (or you must use the combination of `protocol` + `forwarder` to identify the record).
- **`preference` for MX defaults to `1`** when missing, not to the current value. This could silently change the preference if omitted.
- The API docs reference `SCVB` in some parameter descriptions -- this is a typo for `SVCB`.