REST API Domains - edmozley/freeitsm GitHub Wiki

๐ŸŒ REST API: Domains

The usage guide for the Domains module of the REST API: the domain register, registry lookups, the security checks and their findings, and each domain's history. Mirrors the interactive documentation at System โ†’ API โ†’ Documentation.

[!NOTE] New to the API? The basics table on REST API: Tickets covers base URL, authentication, the response envelope, error codes, rate limits and PATCH semantics - identical across all modules.

What's distinctive about Domains:

๐Ÿข Company-scoped Lists are filtered to the key's companies; a domain outside them is a 404 on every by-id route. New domains land in company_id (checked against the key) or the key's default company.
๐Ÿ” Auth codes never cross the API Responses carry only auth_code_set; a body containing auth_code is refused with 422. A transfer secret belongs behind the analyst permission and its audit trail.
๐Ÿ”Ž Lookups and checks on demand POST /domains/{id}/lookup asks the registry now; POST /domains/{id}/check re-grades now. Both return the domain with what changed.
๐Ÿ“œ Findings in English GET /domains/{id}/findings returns each finding's title and advice filled in, for a consumer with no language file.

Give a key the Domains permissions (read / create / update / delete, and internal for internal monitoring) under System โ†’ API.


๐Ÿš€ Quick start

B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โ€ฆ"

# Everything expiring in the next 60 days, soonest first
curl -s -H "$K" "$B/domains?expiring_within_days=60&sort=expiry_date" | jq '.data[] | {domain_name, expiry_date, days_remaining}'

# Add a domain and fill in the registry details straight away
curl -s -H "$K" -H "Content-Type: application/json" -X POST \
     -d '{"domain_name":"example.com","purpose":"primary","lookup":true}' "$B/domains"

# What is wrong with it, and how to fix it
curl -s -H "$K" "$B/domains/42/findings" | jq '.data[] | select(.level=="fail" or .level=="warn") | {title, advice}'

Endpoints

Method Path Permission What
GET /domains domains.read List / search
POST /domains domains.create Add a domain
GET /domains/{id} domains.read One domain
PATCH /domains/{id} domains.update Change fields
DELETE /domains/{id} domains.delete Delete (with its history)
POST /domains/{id}/lookup domains.update Refresh from the registry
POST /domains/{id}/check domains.update Run the checks now
GET /domains/{id}/findings domains.read The last check's findings
GET /domains/{id}/history domains.read Every change, newest first
GET /domain-statuses domains.read Statuses (alerts_enabled marks the ones that stop reminders)
GET /domain-registrar-accounts domains.read Registrar accounts (company-scoped; no passwords exist to return)
GET /domains/{id}/endpoints domains.read An internal domain's HTTPS endpoints and their last results
POST /domains/{id}/endpoints domains.internal Add an endpoint
PATCH /domains/{id}/endpoints/{endpoint_id} domains.internal Change an endpoint (partial)
DELETE /domains/{id}/endpoints/{endpoint_id} domains.internal Remove an endpoint
GET /domains/{id}/expected-records domains.read An internal domain's expected DNS records
POST /domains/{id}/expected-records domains.internal Add an expected record
PATCH /domains/{id}/expected-records/{record_id} domains.internal Change an expected record (partial)
DELETE /domains/{id}/expected-records/{record_id} domains.internal Remove an expected record
GET /domain-trust-profiles domains.internal Trust profiles, with each CA's name and expiry (never the certificates)
POST /domain-trust-profiles domains.internal Add a trust profile
PATCH /domain-trust-profiles/{id} domains.internal Rename it, or replace its certificates
DELETE /domain-trust-profiles/{id} domains.internal Delete it (refused while an endpoint uses it)

The last twelve are internal monitoring; every domains.internal route also needs the key's analyst to hold the Internal monitoring permission.

List filters

q, domain_name (tidied like input, so a URL matches - and with split DNS it can return two records, one per scope), scope (public or internal), status_id, owner_analyst_id, registrar_supplier_id, registrar_account_id, purpose, tag, expiring_within_days, expired=true, transfer_lock=true|false, grade=D,F, company_id, sort (expiry_date default, domain_name, security_score, ssl_expiry_date, created_at, id; prefix - for descending), page / per_page.

Writes

Only domain_name is required on create. A name may exist once as "scope": "public" and once as "scope": "internal" in a company (split DNS); a second record of the same name and scope is a 409 conflict, as is changing a record's scope while its twin holds that scope. Lookups (status_id, owner_analyst_id, registrar_supplier_id, registrar_account_id, tech_contact_id, tech_analyst_id, contract_id, customer_user_id, customer_supplier_id, customer_contact_id) are validated with a 422 naming the field. customer_user_id is the domain's customer โ€” a user in the domain's own company โ€” and comes back as customer: {id, name, email}.

Customer and technical contact (3.1.0, #162). A domain has one customer โ€” customer_user_id, or customer_supplier_id with an optional customer_contact_id โ€” and one technical contact โ€” tech_contact_id (a supplier contact) or tech_analyst_id. Setting one kind clears the other, so a PATCH need only name the new one; naming both kinds in one request is a 422. A customer_contact_id on its own sets customer_supplier_id to that contact's supplier; a contact from a different supplier than the one you name is a 422. Clearing customer_supplier_id clears its contact too. The responses keep customer and tech_contact exactly as before and add tech_analyst: {id, name}, customer_supplier: {id, name} and customer_contact: {id, name, email} beside them, each null when not set. Before Database Verification has added the columns, the three new fields are accepted and ignored. Dates are YYYY-MM-DD. purpose is one of primary, secondary, redirect, email_only, defensive, parked, campaign; renewal_mode one of auto, manual, do_not_renew, unknown. On PATCH, omit a field to leave it, send "" or null to clear it.

Every write goes through the same service as the screens: the same validation, a history row per changed field (source api), and the domain.created / domain.updated / domain.deleted workflow events.

Cost centre (3.9.0, #188). Send cost_centre_id - a cost centre of the domain's own company - or cost_centre with its code ("0010"), which is looked up in that company and refused with a 422 if it does not exist. Send "" or null to clear it. Responses carry cost_centre_id and cost_centre_label ("0010 Finance"), plus cost_centre: the free text recorded before 3.9.0, kept until a real cost centre is chosen. See Cost centres.

Errors

HTTP code When
400 invalid_parameter unknown sort or purpose
403 forbidden company_id outside the key's scope
404 not_found no such domain, or outside the key's companies
409 conflict the name is already in the register for that company
422 invalid_field / missing_field bad value, unknown id, empty PATCH - or auth_code in the body
502 lookup_failed the registry did not answer, rate-limited, or has no such registration

Internal monitoring (4.9.0)

For an internal domain (Domains - Internal domains): the HTTPS endpoints whose certificates (and, optionally, one page) are checked, the DNS records each name is expected to hold, and the trust profiles - your own certificate authorities - that endpoints are checked against.

Who may do what. Reading a domain's endpoints and expected records needs only domains.read: everybody who can see the domain sees the results. Everything else needs domains.internal and the analyst the key acts as must hold the Internal monitoring permission (System โ†’ Roles) - endpoints decide which internal addresses the server connects to, so a key can never do here what its analyst could not do on screen. Trust profiles serve every company, so on a multi-company install only a key with no company limit may change them.

Endpoints. Body fields: host (the domain or a name under it - a name, never an address), port (default 443; checked against the permitted ports when the check runs), warn_days (1-120, default 21), trust_profile_id (null for the server's normal CA bundle), and the optional HTTP check: http_path (starts with /, no spaces) and http_expect (status codes such as "200, 204", 200 when empty; stored tidied). The page is asked only after the certificate passes, only its status is read, and a redirect is never followed - list a 3xx if that is the right answer. Responses carry status (healthy, expiring, problem or null - the last completed result), not_checked_since (the latest attempt could not run), detail (why, e.g. untrusted, http_status, network_refused), address, certificate and the last_attempt_at / last_completed_at / last_healthy_at dates. Changing the host, port, trust profile or HTTP check clears the old results: they described a different target.

Expected records. host, record_type (A, AAAA, CNAME, NS, SOA) and expected_values - a list (text one per line is accepted too). An empty list means the record only has to exist. Values are stored normalised and sorted; an invalid value is a 422 naming it; CNAME and SOA take one value. The result of each is a finding in GET /domains/{id}/findings (int_expected_ok, _missing, _mismatch, _not_checked).

Trust profiles. name and ca_pem (one or more -----BEGIN CERTIFICATE----- blocks; a private key is refused). Responses return summary (each CA's name and expiry) and used_by, never the certificates. A PATCH without ca_pem renames the profile and keeps its certificates.

PATCH is partial on all three: omitted fields keep their stored values, then the same rules as the screen run. Send null to clear http_path.

HTTP code When
403 forbidden no domains.internal; the key's analyst lacks Internal monitoring; a company-limited key changing a trust profile
404 not_found no such domain (or outside the key's companies), endpoint, expected record or trust profile
422 not_ready Database Verification has not been run since upgrading
422 not_internal an endpoint or expected record on a public domain
422 duplicate the same host and port, or the same name and type, twice
422 in_use deleting a trust profile an endpoint uses
422 the field's name a value the screen would refuse, with the same message

How it is built: Internal Domain Monitoring - Developer Guide.

See also: Domains ยท Domains developer guide ยท REST API