Skip to main content

Import a DNS zone file into a Project, or preview it with dry-run

POST/v2/projects/{projectId}/dns-zone-imports
API version
v2
Request method
POST
Operation ID
dns-create-dns-zone-file-import

Parses an uploaded RFC-1035 zone file and returns the structured import plan: the importable target DNSZones (one per distinct owner name, with the record sets that would be set) plus a flat list of conflicts explaining everything that will not be imported (invalid records, unsupported record types, CNAME conflicts, placement problems, parse errors). With dryRun=true this is all it does — a side-effect-free preview, nothing is created. Otherwise it also starts the import and returns the created job id. The import is all-or-nothing: if the zone file has any conflict the request is rejected with 412 and no job is created — resolve the conflicts (visible in the dry-run preview) and retry, since a half-imported zone file would leave DNS in a confusing half-state. An identical import still running for the project is rejected with 409. Existing zones are overwritten. Poll GET /v2/dns-zone-imports/{zoneFileImportId} for status.

Request​

  • projectIdstring
    required

    ID of the Project to import into.

Responses​

Format
application/json
Description

The import plan (zones + conflicts); on a real import also the created job id.

  • conflictsarray of object
    required

    Everything that will not be imported (invalid records, unsupported record types, CNAME conflicts, placement problems, parse errors). Empty on a real import, since any conflict rejects the whole import with 412 (all-or-nothing).

    • Array[
      • *object
        • codestring (one of: parseError, invalidRecord, invalidZoneName, unsupportedRecordType, cnameConflict, foreignCustomerIngress, rootZoneUnavailable)
          required

          Machine-readable conflict kind: parseError (a zone-file line could not be parsed), invalidRecord (a record failed the same schema validation the write commands apply), invalidZoneName (the owner name is not a valid zone name, e.g. a wildcard *.example.com), unsupportedRecordType (an RR type dns-service does not import), cnameConflict (a CNAME shares a name with other record types), foreignCustomerIngress (the zone's enabled ingress belongs to another organization), rootZoneUnavailable (a subzone whose root zone is neither importable nor already existing).

        • messagestring
          required

          Human-readable explanation of the conflict, suitable for surfacing to the user.

        • namestring

          Offending record/owner name. Empty for a file-level parse error, where sourceLine locates the bad line.

        • recordstring

          Only on an invalidRecord conflict: the offending record's rendered value (e.g. "10 ." for an MX).

        • recordSetTypestring (one of: a, mx, txt, cname, srv, caa)

          Only on an invalidRecord conflict: the offending record's set type.

        • sourceLineinteger (int64)

          1-based line number in the uploaded zone file, set for a file-level parse error (code parseError); 0 otherwise.

      ]
  • idstring (uuid)

    ID of the started import job. Absent on a dry-run (dryRun=true), which creates no job.

  • zonesarray of object
    required

    The importable target zones (one per distinct owner name), each with the record sets that would be set. On a dry-run this is the preview; on a real import it is the plan that was applied.

    • Array[
      • *object
        • alreadyExistsboolean
          required

          Whether a zone with this name already exists. On import its record sets are overwritten rather than the import failing.

        • namestring
          required

          Fully-qualified name of the target zone. Every distinct owner name becomes its own zone. Only importable zones are listed; a zone named by a conflict is omitted.

        • recordSetsarray of object
          required

          The record sets that would be set on the zone — one per record type present for this owner name.

          • Array[
            • *object
              • recordsarray of object
                required

                The individual records in the set.

                • Array[
                  • *object
                    • flagsinteger (int32)

                      CAA flags. Only set for CAA records.

                    • portinteger (int32)

                      SRV port. Only set for SRV records.

                    • priorityinteger (int32)

                      MX preference / SRV priority. Only set for MX and SRV records.

                    • tagstring

                      CAA tag (e.g. issue, issuewild, iodef). Only set for CAA records.

                    • valuestring
                      required

                      The record's value: an IP address for A/AAAA, the target FQDN for MX/CNAME/SRV, the text for TXT, the value for CAA.

                    • weightinteger (int32)

                      SRV weight. Only set for SRV records.

                  ]
              • ttlNormalizedboolean
                required

                True when the source TTLs had to be normalized to ttlSeconds — because they diverged within the set or fell below the 60s minimum. Informational; the import still uses ttlSeconds.

              • ttlSecondsinteger (int32)
                required

                TTL applied to the whole set, in seconds. Collapsed to a single value across the set: the minimum of the source TTLs, floored to the 60s minimum.

              • typestring (one of: a, mx, txt, cname, srv, caa)
                required

                Record-set type.

            ]
        • targetProjectIdstring
          required

          Project the zone would be created in. Always set, since only importable zones are listed.

      ]
Content-Type: application/json

{
"conflicts": [
{
"code": "parseError",
"message": "string",
"name": "string",
"record": "string",
"recordSetType": "a",
"sourceLine": 123
}
],
"id": "f0f86186-0a5a-45b2-aa33-502777496347",
"zones": [
{
"alreadyExists": true,
"name": "string",
"recordSets": [
{
"records": [
{
"flags": 123,
"port": 123,
"priority": 123,
"tag": "string",
"value": "string",
"weight": 123
}
],
"ttlNormalized": true,
"ttlSeconds": 123,
"type": "a"
}
],
"targetProjectId": "string"
}
]
}
{
"properties": {
"conflicts": {
"description": "Everything that will not be imported (invalid records, unsupported record types, CNAME conflicts, placement problems, parse errors). Empty on a real import, since any conflict rejects the whole import with 412 (all-or-nothing).",
"items": {
"properties": {
"code": {
"description": "Machine-readable conflict kind: parseError (a zone-file line could not be parsed), invalidRecord (a record failed the same schema validation the write commands apply), invalidZoneName (the owner name is not a valid zone name, e.g. a wildcard *.example.com), unsupportedRecordType (an RR type dns-service does not import), cnameConflict (a CNAME shares a name with other record types), foreignCustomerIngress (the zone's enabled ingress belongs to another organization), rootZoneUnavailable (a subzone whose root zone is neither importable nor already existing).",
"enum": [
"parseError",
"invalidRecord",
"invalidZoneName",
"unsupportedRecordType",
"cnameConflict",
"foreignCustomerIngress",
"rootZoneUnavailable"
],
"type": "string"
},
"message": {
"description": "Human-readable explanation of the conflict, suitable for surfacing to the user.",
"type": "string"
},
"name": {
"description": "Offending record/owner name. Empty for a file-level parse error, where sourceLine locates the bad line.",
"type": "string"
},
"record": {
"description": "Only on an invalidRecord conflict: the offending record's rendered value (e.g. \"10 .\" for an MX).",
"type": "string"
},
"recordSetType": {
"description": "Only on an invalidRecord conflict: the offending record's set type.",
"enum": [
"a",
"mx",
"txt",
"cname",
"srv",
"caa"
],
"type": "string"
},
"sourceLine": {
"description": "1-based line number in the uploaded zone file, set for a file-level parse error (code parseError); 0 otherwise.",
"format": "int64",
"type": "integer"
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"type": "array"
},
"id": {
"description": "ID of the started import job. Absent on a dry-run (dryRun=true), which creates no job.",
"format": "uuid",
"type": "string"
},
"zones": {
"description": "The importable target zones (one per distinct owner name), each with the record sets that would be set. On a dry-run this is the preview; on a real import it is the plan that was applied.",
"items": {
"properties": {
"alreadyExists": {
"description": "Whether a zone with this name already exists. On import its record sets are overwritten rather than the import failing.",
"type": "boolean"
},
"name": {
"description": "Fully-qualified name of the target zone. Every distinct owner name becomes its own zone. Only importable zones are listed; a zone named by a conflict is omitted.",
"type": "string"
},
"recordSets": {
"description": "The record sets that would be set on the zone — one per record type present for this owner name.",
"items": {
"properties": {
"records": {
"description": "The individual records in the set.",
"items": {
"properties": {
"flags": {
"description": "CAA flags. Only set for CAA records.",
"format": "int32",
"type": "integer"
},
"port": {
"description": "SRV port. Only set for SRV records.",
"format": "int32",
"type": "integer"
},
"priority": {
"description": "MX preference / SRV priority. Only set for MX and SRV records.",
"format": "int32",
"type": "integer"
},
"tag": {
"description": "CAA tag (e.g. issue, issuewild, iodef). Only set for CAA records.",
"type": "string"
},
"value": {
"description": "The record's value: an IP address for A/AAAA, the target FQDN for MX/CNAME/SRV, the text for TXT, the value for CAA.",
"type": "string"
},
"weight": {
"description": "SRV weight. Only set for SRV records.",
"format": "int32",
"type": "integer"
}
},
"required": [
"value"
],
"type": "object"
},
"type": "array"
},
"ttlNormalized": {
"description": "True when the source TTLs had to be normalized to ttlSeconds — because they diverged within the set or fell below the 60s minimum. Informational; the import still uses ttlSeconds.",
"type": "boolean"
},
"ttlSeconds": {
"description": "TTL applied to the whole set, in seconds. Collapsed to a single value across the set: the minimum of the source TTLs, floored to the 60s minimum.",
"format": "int32",
"type": "integer"
},
"type": {
"description": "Record-set type.",
"enum": [
"a",
"mx",
"txt",
"cname",
"srv",
"caa"
],
"type": "string"
}
},
"required": [
"type",
"ttlSeconds",
"ttlNormalized",
"records"
],
"type": "object"
},
"type": "array"
},
"targetProjectId": {
"description": "Project the zone would be created in. Always set, since only importable zones are listed.",
"type": "string"
}
},
"required": [
"name",
"alreadyExists",
"recordSets",
"targetProjectId"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"zones",
"conflicts"
],
"type": "object"
}

Usage examples​

$ curl \
--fail \
--location \
-X POST \
-d '{"zoneFile":"string"}' \
-H "Authorization: Bearer $MITTWALD_API_TOKEN" \
-H 'Content-Type: application/json' \
https://api.mittwald.de/v2/projects/string/dns-zone-imports?dryRun=true
import { MittwaldAPIV2Client } from "@mittwald/api-client";
import { assertStatus } from "@mittwald/api-client-commons";

const client = MittwaldAPIClient.newWithToken(process.env.MITTWALD_API_TOKEN);
const response = await client.domain.dnsCreateDnsZoneFileImport({
"projectId": "string",
"data": {
"zoneFile": "string"
},
"queryParameters": {
"dryRun": true
}
});

assertStatus(response, 200);

use \Mittwald\ApiClient\Generated\V2\Clients\Domain\DnsCreateDnsZoneFileImport\DnsCreateDnsZoneFileImportRequest;
use \Mittwald\ApiClient\Generated\V2\Clients\Domain\DnsCreateDnsZoneFileImport\DnsCreateDnsZoneFileImportRequestBody;

$client = MittwaldAPIClient::newWithToken(getenv('MITTWALD_API_TOKEN'));

// TODO: Please consult the properties and constructor signature of
// DnsCreateDnsZoneFileImportRequestBody to learn how to construct a valid instance
$body = new DnsCreateDnsZoneFileImportRequestBody(/* TODO: ... */);

$request = (new DnsCreateDnsZoneFileImportRequest(
projectId: "string",
body: $body
))
->withDryRun(true);
$response = $client->domain()->dnsCreateDnsZoneFileImport($request);

var_dump($response->getBody();

On this page