Update domain contacts

POST /api/v2/domains/{id}/contacts

Update one or more contact roles on a domain.

This is an update endpoint, not a contact creation endpoint: send at least one of registrant, admin, tech, or billing, and only the documented camelCase v2 contact fields.

Unknown fields and legacy internal contact aliases are rejected on this per-domain route.

For .se, .nu, and .test domains, changing a valid Swedish registrant personal or organisation number requires identity verification; when the identifier is preserved instead of applied, the response reports this in updateOutcome.registrantRegistrationIdentifierApplied: false and updateOutcome.registrantRegistrationIdentifierBlockedReason: "identity_verification_required".

If the current identifier cannot be verified by BankID and registry contact-details verification is currently required, the registrant identifier can be corrected directly.

Submitting a DIFFERENT registrant identifier on a .se/.nu domain starts an in-place registered-holder change (the domain stays on the same account): it requires consent from the current holder (verification link or matching BankID), a fresh BankID session proving the caller is the new holder or its company signatory, and acceptedRegistryTerms containing the registry-terms key.

Until all three are present the endpoint responds with problem code holder_change_verification_required whose holderChange object lists what is missing.

When the new holder is an organisation the company registry holds no signatory data for (ideella föreningar, stiftelser, trossamfund), BankID cannot prove representation: holderChange.requiresBankId is false and holderChange.signatoryReview is present (required: true, companyName, submitDocumentsPath — a prefilled support-ticket link for submitting protokoll/stadgar).

After staff approve the new holder from the reviewed documents, resubmitting the same request completes the change (evidence method staff_documented).

A verified mismatch against an organisation that DOES have signatory data responds with registrant_transfer_required (use the ownership-transfer flow instead).

A completed holder change is reported as updateOutcome.holderChanged: true.

Successful responses echo the full contacts payload with current action gates and contactDetailsVerification.

Domains & DNS Domains

Authentication

Required API scope: write:domains

Authenticate with an API key in the Authorization: Bearer <token> header.

Context

Path Parameters

id string required Example: dom_01hxa3b4c5d6e7f8g9h0j1k2m3

Public domain ID. Get it from GET /api/v2/domains data[].id. Do not invent this value; use the exact ID returned by the referenced API response.

Headers

Authorization Bearer <token>
Accept application/json
Content-Type application/json

Body

required
application/json
registrant null
admin null
tech null
billing null
acceptedRegistryTerms array<string>

Registry-terms acceptance for an in-place registered-holder change on .se/.nu domains (e.g. ["se_registration_terms"]). Send the key from the holder_change_verification_required problem's holderChange.terms.key after the customer ticks the terms checkbox. Ignored for ordinary contact edits.

Responses

200 Contacts updated. Wrapperless v2 response.
registrant null
admin null
tech null
billing null
draft boolean · Example: false

True for pending-registration Swedish TLD drafts where registrant contact data can still be edited before payment or registry sync.

serviceStatus string · enum · Example: active

Canonical v2 service lifecycle status for the domain contact resource.

active
suspended
expired
pending
cancelled
terminated
unknown
contactDetailsVerification null

Fresh registry contact-details verification state for this domain contact resource, or null when no contact review is currently required.

actions object
actions.canEditContacts object required

False while contact changes are locked, for example during an in-progress transfer.

actions.canEditContacts.allowed boolean required · Example: true
actions.canEditContacts.reason string · nullable required · Example: null

Nullable: may be null when not applicable.

actions.canEditContacts.code string · nullable · Example: pending_order

Machine-readable reason code when an action is blocked.

actions.requiresIdentityVerification object required

allowed: true means identity verification, currently BankID for .se/.nu/.test registrant identifier changes, is required before the registrant personal or organisation number can be updated.

actions.requiresIdentityVerification.allowed boolean required · Example: true
actions.requiresIdentityVerification.reason string · nullable required · Example: null

Nullable: may be null when not applicable.

actions.requiresIdentityVerification.code string · nullable · Example: pending_order

Machine-readable reason code when an action is blocked.

updateOutcome null
400 Invalid request. The response body is an RFC 7807 Problem Details document.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
401 Unauthorized. Authentication is required.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
403 Forbidden. The caller lacks a required scope or does not own the resource.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
404 Not found. The resource does not exist or is not owned by the caller; code is domain_not_found.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
429 Rate limited. Retry after the limit resets. 429 responses include Retry-After seconds plus X-RateLimit-* headers.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
500 Internal error. Retry later or contact support if the issue persists.
type string · Example: https://developer.hostup.se/errors/invalid_request
title string · Example: Validation failed
status integer · Example: 400
detail string · Example: The request body failed validation.
code string · Example: invalid_request

Stable machine-readable code. Branch on this field, not on detail.

instance string · Example: /api/v2/orders
requestId string · Example: req_01hxa3b4c5d6e7f8g9h0j1k2m3
timestamp string · Example: 2026-04-27T12:34:56.000Z
errors array<object>

Field-level validation errors when code is invalid_request.

errors[].pointer string required · Example: /items/0/eppCode
errors[].detail string required · Example: `eppCode` is required for this transfer.
errors[].code string required · Example: missing_required
extensions object
POST https://cloud.hostup.se/api/v2/domains/{id}/contacts
For AI assistants
View as Markdown
cURL
curl -X POST "https://cloud.hostup.se/api/v2/domains/dom_01hxa3b4c5d6e7f8g9h0j1k2m3/contacts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "registrant": {
      "firstName": "Anna",
      "lastName": "Svensson",
      "companyName": "Example AB",
      "email": "[email protected]",
      "phoneNumber": "+46700000000",
      "street": "Examplegatan 1",
      "city": "Stockholm",
      "postalCode": "12345",
      "countryCode": "SE"
    }
  }'
Response
{
  "registrant": {
    "firstName": "Anna",
    "lastName": "Svensson",
    "companyName": "Example AB",
    "email": "[email protected]",
    "phoneNumber": "+46700000000",
    "street": "Examplegatan 1",
    "address2": "5",
    "city": "Goteborg",
    "postalCode": "413 04",
    "state": "Vastra Gotaland",
    "countryCode": "SE",
    "registrationIdentifier": {
      "value": "559290-1325",
      "countryCode": "SE",
      "type": "organization_number"
    }
  },
  "admin": null,
  "tech": null,
  "billing": null,
  "draft": false,
  "serviceStatus": "active",
  "contactDetailsVerification": null,
  "actions": {
    "canEditContacts": {
      "allowed": true,
      "reason": null
    },
    "requiresIdentityVerification": {
      "allowed": true,
      "reason": "BankID verification is required before updating the registrant's personal or organisation number."
    }
  },
  "updateOutcome": {
    "syncTriggered": false,
    "orderActivation": null,
    "registrantRegistrationIdentifierApplied": false,
    "registrantRegistrationIdentifierBlockedReason": "identity_verification_required",
    "holderChanged": false
  }
}
Request Body Update registrant contact fields
{
  "registrant": {
    "firstName": "Anna",
    "lastName": "Svensson",
    "companyName": "Example AB",
    "email": "[email protected]",
    "phoneNumber": "+46700000000",
    "street": "Examplegatan 1",
    "city": "Stockholm",
    "postalCode": "12345",
    "countryCode": "SE"
  }
}