srs

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package srs wraps the SiteHost /srs API — domain registration, transfer, contacts, and lifecycle ops via the Shared Registry System.

TLD-policy variation (important)

SiteHost's SRS API is a uniform façade over multiple upstream-registry policies — but **not all features apply to every TLD** the registry serves. The API doesn't surface a per-TLD capability matrix; consumers learn about restrictions only when an op rejects with a TLD-specific error message.

Confirmed TLD-specific behaviours (May 2026):

  • **.nz domains reject LockDomain / UnlockDomain** with "This domain cannot be locked." The .nz registry uses the UDAI (transfer authorisation code) model rather than EPP-style transfer locks. Use NewUDAI / ValidateUDAI for transfer auth on .nz instead.

  • Other TLD-specific quirks are likely (privacy-protection not supported on some TLDs, contact-update rules differing between registries, etc.) but haven't been exhaustively catalogued. Treat any "this domain cannot ..." error as a TLD-policy signal, not a wrapper bug.

**Consumer guidance:** for each write op, call once and check the response. Don't assume a wrapper that works on .com works identically on .nz / .au / .uk / etc. The wrapper produces the well-formed request; the API enforces TLD policy on top.

**Open question for the API team:** could there be a per-TLD capability endpoint so SDK consumers know upfront which ops will be rejected?

Endpoint surface in this package

Reads: ListDomains, GetDomain, ListContacts, GetContact, SearchContacts, ListNameServers, ListValidTLDs, GetPricingTiers, GetCompanyInfo, Whois, GetDomainPrice, DomainAvailable, DomainInsideGracePeriod, CanTransferDomain.

Writes: CreateDomain, CancelDomain, LockDomain, UnlockDomain, EnablePrivacyProtection, DisablePrivacyProtection, UpdateAutoRenew. (More writes — contacts CRUD, transfer flow, UDAI, name servers — coming in Tier 2+.)

Index

Constants

This section is empty.

Variables

View Source
var ErrEmailTemplateUnsupported = errors.New(
	"srs.GetEmailTemplate: endpoint not currently usable — " +
		"every probed input form is rejected by the API with " +
		"\"The specified template doesnt exist, or you dont have " +
		"access to it.\" (sic). Use ListEmailTemplates to read " +
		"template bodies until the expected input form is clarified",
)

ErrEmailTemplateUnsupported is returned by GetEmailTemplate to signal that the underlying API endpoint is not currently usable from this SDK. The lookup-key namespace expected by /srs/get_email_templates.json appears disjoint from anything surfaced by ListEmailTemplates (numeric template_id, type slug, human name — none accepted), and there's no documented form that satisfies it. Use ListEmailTemplates to read template bodies in the meantime.

Match with errors.Is so the SDK can lift this to a real implementation later without a breaking change at the call site.

Functions

This section is empty.

Types

type AddNameServersOptions

type AddNameServersOptions struct {
	Domain      string
	NameServers []NameServerEntry
}

AddNameServersOptions adds one or more nameservers to a domain. Domain and at least one entry in NameServers are required.

The wire format is array-indexed:

nameservers[0][name]=ns1.example.com
nameservers[0][ipv4addr]=192.0.2.1     (optional, glue only)
nameservers[1][name]=ns2.example.com
...

Add is additive — existing nameservers are preserved unless the registry replaces them. To replace the full set, you typically remove (registry-side; not currently exposed) and re-add.

type BoolResponse

type BoolResponse struct {
	Return bool `json:"return"`
	models.APIResponse
}

BoolResponse is the response shape used by domain_available and domain_inside_grace_period — Return is just a bool.

type CanTransferDomainInfo

type CanTransferDomainInfo struct {
	Domain      string `json:"domain"`
	CanTransfer bool   `json:"can_transfer"`
	Reason      string `json:"reason"`
}

CanTransferDomainInfo describes transfer eligibility.

type CanTransferDomainResponse

type CanTransferDomainResponse struct {
	Return CanTransferDomainInfo `json:"return"`
	models.APIResponse
}

CanTransferDomainResponse represents the response from can_transfer_domain.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a Service to work with the SiteHost SRS API.

func New

func New(c *api.Client) *Client

New is an initialisation function.

func (*Client) AddNameServers

func (s *Client) AddNameServers(ctx context.Context, opt AddNameServersOptions) (response models.APIResponse, err error)

AddNameServers attaches one or more nameservers to a domain via "srs/add_name_servers.json".

func (*Client) CanTransferDomain

func (s *Client) CanTransferDomain(ctx context.Context, opt DomainOptions) (response CanTransferDomainResponse, err error)

CanTransferDomain reports whether a domain can be transferred in via "srs/can_transfer_domain.json". Domain is required.

func (*Client) CancelDomain

func (s *Client) CancelDomain(ctx context.Context, opt DomainOptions) (response JobResponse, err error)

CancelDomain cancels a domain registration via "srs/cancel_domain.json". Domain is required. Returns a JobResponse with the scheduler job ID for tracking the asynchronous cancellation.

For .nz domains cancelled within 5 days of registration, no billing is incurred. Outside that window, billing rules apply per the registry.

func (*Client) CreateContact

func (s *Client) CreateContact(ctx context.Context, opt CreateContactOptions) (response CreateContactResponse, err error)

CreateContact registers a new domain contact via "srs/create_contact.json". Returns the new contact's id.

Contact fields outside the required set may be left empty; a follow-up UpdateContact can fill them in.

func (*Client) CreateDomain

func (s *Client) CreateDomain(ctx context.Context, opt CreateDomainOptions) (response JobResponse, err error)

CreateDomain registers a new domain via "srs/create_domain.json". Domain and all four contact IDs (RegistrantContact, AdminContact, TechnicalContact, BillingContact) are required.

**This is destructive.** Successful registration incurs a real registry charge. For .nz domains, registrations cancelled within 5 days of creation are not billed (per registry grace-period rules); other TLDs vary. The account must hold sufficient funds at registration time regardless.

Returns a JobResponse with the scheduler job ID for tracking the asynchronous registration.

func (*Client) DeleteContact

func (s *Client) DeleteContact(ctx context.Context, opt DeleteContactOptions) (response models.APIResponse, err error)

DeleteContact removes a domain contact via "srs/delete_contact.json". The API rejects deletion of contacts currently bound to any domain — unbind first via UpdateDomainContacts.

func (*Client) DisablePrivacyProtection

func (s *Client) DisablePrivacyProtection(ctx context.Context, opt PrivacyOptions) (response models.APIResponse, err error)

DisablePrivacyProtection turns WHOIS privacy off via "srs/disable_privacy_protection.json". Same Reason-required shape as EnablePrivacyProtection.

func (*Client) DomainAvailable

func (s *Client) DomainAvailable(ctx context.Context, opt DomainAvailableOptions) (response BoolResponse, err error)

DomainAvailable reports whether a domain is registrable via "srs/domain_available.json". Domain is required.

func (*Client) DomainInsideGracePeriod

func (s *Client) DomainInsideGracePeriod(ctx context.Context, opt DomainOptions) (response BoolResponse, err error)

DomainInsideGracePeriod reports whether a domain is in the post-cancellation grace period via "srs/domain_inside_grace_period.json". Domain is required.

func (*Client) EnablePrivacyProtection

func (s *Client) EnablePrivacyProtection(ctx context.Context, opt PrivacyOptions) (response models.APIResponse, err error)

EnablePrivacyProtection enables WHOIS privacy on a domain via "srs/enable_privacy_protection.json". Reason is required by the API even though the field has no externally-visible effect.

Verify the new state via srs.GetDomain(domain).Private (returned as "1" / "0" string).

func (*Client) GetCompanyInfo

func (s *Client) GetCompanyInfo(ctx context.Context) (response GetCompanyInfoResponse, err error)

GetCompanyInfo returns the client's company profile (used in renewal emails and registry contacts) via "srs/get_company_info.json".

func (*Client) GetContact

func (s *Client) GetContact(ctx context.Context, opt ContactOptions) (response GetContactResponse, err error)

GetContact returns the full record for a single contact via "srs/get_contact.json". ContactID is required.

func (*Client) GetDomain

func (s *Client) GetDomain(ctx context.Context, opt DomainOptions) (response GetDomainResponse, err error)

GetDomain returns the full record for a domain via "srs/get_domain.json". Domain is required.

func (*Client) GetDomainPrice

func (s *Client) GetDomainPrice(ctx context.Context, opt DomainOptions) (response GetDomainPriceResponse, err error)

GetDomainPrice returns pricing for a domain via "srs/get_domain_price.json". Domain is required.

func (*Client) GetEmailTemplate

func (s *Client) GetEmailTemplate(_ context.Context, opt GetEmailTemplateOptions) (response GetEmailTemplateResponse, err error)

GetEmailTemplate is the wrapper for "srs/get_email_templates.json" (GET) — note the trailing 's' on "templates" even for a single- template lookup.

**Currently unusable.** Live probing (May 2026) exhausted every plausible value derived from ListEmailTemplates output — the numeric `template_id` ("11239" or its "-13" prefixed form), the type slug ("AutoRenewReminder"), the lowercase variant, the human name ("Auto-Renew Reminder - 7 Days") — and every one was rejected with

200 Error: The specified template doesnt exist, or you dont
have access to it.

(sic — API text omits the apostrophes). The lookup-key namespace for this endpoint appears disjoint from anything ListEmailTemplates surfaces.

To avoid relying on doc-comment-only warnings, the wrapper short-circuits and returns ErrEmailTemplateUnsupported without making the API call. Consumers can detect this with errors.Is. When the upstream input shape is clarified, the wrapper can be switched to making the real call without breaking call sites.

func (*Client) GetPricingTiers

func (s *Client) GetPricingTiers(ctx context.Context) (response GetPricingTiersResponse, err error)

GetPricingTiers returns the count→price tier map for domain registrations via "srs/get_pricing_tiers.json".

func (*Client) ListContacts

func (s *Client) ListContacts(ctx context.Context) (response ListContactsResponse, err error)

ListContacts returns all contacts for the authenticated client via "srs/list_contacts.json".

func (*Client) ListDomains

func (s *Client) ListDomains(ctx context.Context, opt *ListDomainsOptions) (response ListDomainsResponse, err error)

ListDomains retrieves the list of domains registered for the authenticated client via "srs/list_domains.json".

opt may be nil (returns the default page with default sort); otherwise SortBy / SortDir / PageSize / PageNumber narrow or reorder the result.

The endpoint is documented at https://docs.sitehost.nz/api/v1.5/?path=/srs. The per-endpoint reference page is sparse at the time of writing — field shapes here mirror the production API's responses.

func (*Client) ListEmailTemplates

func (s *Client) ListEmailTemplates(ctx context.Context) (response ListEmailTemplatesResponse, err error)

ListEmailTemplates returns all email templates configured for the authenticated client via "srs/list_email_templates.json" (GET). The template body and subject are returned per template alongside its name.

The public docs do not list parameters; only client_id (auto- injected by the SDK). Validate the response shape live before depending on field names.

func (*Client) ListNameServers

func (s *Client) ListNameServers(ctx context.Context, opt DomainOptions) (response ListNameServersResponse, err error)

ListNameServers returns the nameserver delegation for a domain via "srs/list_name_servers.json". Domain is required.

func (*Client) ListValidTLDs

func (s *Client) ListValidTLDs(ctx context.Context) (response ListValidTLDsResponse, err error)

ListValidTLDs returns the list of TLDs the client may register via "srs/list_valid_tlds.json".

func (*Client) LockDomain

func (s *Client) LockDomain(ctx context.Context, opt DomainOptions) (response models.APIResponse, err error)

LockDomain places a transfer lock on a domain via "srs/lock_domain.json". Lock prevents transfer-out attempts at the registry until the domain is unlocked. Synchronous; the response is a bare {status, msg} envelope (no scheduler job).

**TLD-policy gotcha (verified live):** **.nz domains reject this call** with "This domain cannot be locked." The .nz registry uses the UDAI (transfer authorisation code) model rather than EPP-style transfer locks, so transfer protection is achieved by withholding the UDAI rather than by locking. Other gTLDs (.com, .net, etc.) honour the lock as expected.

Verify the new state via srs.GetDomain(domain).DateLocked (empty / zero-date when unlocked).

func (*Client) NewUDAI

func (s *Client) NewUDAI(ctx context.Context, opt NewUDAIOptions) (response models.APIResponse, err error)

NewUDAI generates a fresh UDAI (auth code) for a domain via "srs/new_udai.json". The code is delivered by email to the registrant; it is not returned in the response.

func (*Client) RenewDomain

func (s *Client) RenewDomain(ctx context.Context, opt RenewDomainOptions) (response models.APIResponse, err error)

RenewDomain extends a domain's registration via "srs/renew_domain.json". Returns the bare {status, msg} envelope; the registry update is synchronous.

**Cost warning:** this charges the account. Avoid in tests against billed test domains unless you've confirmed cost is acceptable.

func (*Client) SearchContacts

func (s *Client) SearchContacts(ctx context.Context, opt SearchContactsOptions) (response SearchContactsResponse, err error)

SearchContacts returns contacts matching the given filters via "srs/search_contacts.json". At least one of Name, Email, or RegistrantName must be set.

func (*Client) TLDsAvailable

func (s *Client) TLDsAvailable(ctx context.Context, opt TLDsAvailableOptions) (response TLDsAvailableResponse, err error)

TLDsAvailable performs a multi-TLD availability check via "srs/domain_tlds_available.json" (GET).

func (*Client) TransferDomain

func (s *Client) TransferDomain(ctx context.Context, opt TransferDomainOptions) (response models.APIResponse, err error)

TransferDomain initiates an inbound domain transfer via "srs/transfer_domain.json".

Live-validating this endpoint requires a domain held at another registrar plus a valid UDAI — gosh's test suite stops at unit tests for this reason. The wrapper is intentionally minimal: it forwards the documented parameters as-is.

func (*Client) UnlockDomain

func (s *Client) UnlockDomain(ctx context.Context, opt DomainOptions) (response models.APIResponse, err error)

UnlockDomain releases the transfer lock on a domain via "srs/unlock_domain.json". Same shape as LockDomain — bare {status, msg} envelope, idempotent.

Same .nz caveat applies: .nz registry policy rejects the call (UDAI model, not lock-based transfer auth). See LockDomain.

func (*Client) UpdateAutoRenew

func (s *Client) UpdateAutoRenew(ctx context.Context, opt UpdateAutoRenewOptions) (response models.APIResponse, err error)

UpdateAutoRenew configures the auto-renew schedule for a domain via "srs/update_auto_renew.json".

Verify the new schedule via srs.GetDomain(domain).AutorenewTerm + AutorenewDaysRemaining.

func (*Client) UpdateCompanyInfo

func (s *Client) UpdateCompanyInfo(ctx context.Context, opt UpdateCompanyInfoOptions) (response models.APIResponse, err error)

UpdateCompanyInfo updates account-level company info via "srs/update_company_info.json".

The endpoint affects branding shown in registry whois output and the renewal-email templates. Test against this carefully — mistyped values affect how customers see the account.

Best practice: read current values via srs.GetCompanyInfo first, copy them into UpdateCompanyInfoOptions, change only what you need to change, send the rest unchanged.

func (*Client) UpdateContact

func (s *Client) UpdateContact(ctx context.Context, opt UpdateContactOptions) (response models.APIResponse, err error)

UpdateContact edits an existing domain contact via "srs/update_contact.json". ContactID is required; only the non-zero / non-empty params[*] fields are sent.

func (*Client) UpdateDomain

func (s *Client) UpdateDomain(ctx context.Context, opt UpdateDomainOptions) (response models.APIResponse, err error)

UpdateDomain refreshes a domain record from the registry via "srs/update_domain.json".

func (*Client) UpdateDomainContacts

func (s *Client) UpdateDomainContacts(ctx context.Context, opt UpdateDomainContactsOptions) (response models.APIResponse, err error)

UpdateDomainContacts rebinds the contact roles on a domain via "srs/update_domain_contacts.json".

Note .nz registry policy may restrict registrant-name changes (the registrant is the legal owner; transferring it elsewhere is a special operation, not just a contact update). Other roles (admin, tech, billing) typically rebind freely.

func (*Client) UpdateEmailTemplate

func (s *Client) UpdateEmailTemplate(ctx context.Context, opt UpdateEmailTemplateOptions) (response models.APIResponse, err error)

UpdateEmailTemplate edits an email template via "srs/update_email_template.json" (POST).

func (*Client) ValidateUDAI

func (s *Client) ValidateUDAI(ctx context.Context, opt ValidateUDAIOptions) (response models.APIResponse, err error)

ValidateUDAI checks a UDAI code via "srs/validate_udai.json". Returns the bare {status, msg} envelope; status=true means the code is valid for the domain, false means rejected.

func (*Client) VerifyEmailToken

func (s *Client) VerifyEmailToken(ctx context.Context, opt VerifyEmailTokenOptions) (response models.APIResponse, err error)

VerifyEmailToken confirms a registrant-email verification token via "srs/verify_email_token.json".

func (*Client) Whois

func (s *Client) Whois(ctx context.Context, opt WhoisOptions) (response WhoisResponse, err error)

Whois performs a whois lookup for the given domain via "srs/whois.json". The Domain field of opt is required.

The endpoint is documented at https://docs.sitehost.nz/api/v1.5/?path=/srs. JSON keys in the response use PascalCase (DomainName, Status, RegisteredDate, ...) reflecting the underlying registry schema — see Whois and WhoisContact in whoisresponse.go.

type CompanyInfo

type CompanyInfo struct {
	ClientID             int    `json:"client_id"`
	CompanyName          string `json:"companyname"`
	CompanyURL           string `json:"companyurl"`
	CompanyRenewURL      string `json:"companyrenewurl"`
	CompanyEmail         string `json:"companyemail"`
	CompanyEmailFrom     string `json:"companyemailfrom"`
	CompanyEmailFromName string `json:"companyemailfromname"`
	CompanySupportEmail  string `json:"companysupportemail"`
	CompanyPhone         string `json:"companyphone"`
	CompanyFax           string `json:"companyfax"`
	SendRenewedEmail     string `json:"send_renewed_email"`
	SendInvoice          string `json:"send_invoice"`
}

CompanyInfo describes the client's company profile.

type ContactDetail

type ContactDetail struct {
	ContactID       int    `json:"ContactID"`
	ClientID        string `json:"ClientID"`
	Name            string `json:"Name"`
	RegistrantName  string `json:"RegistrantName"`
	Organization    string `json:"Organization"` //nolint:misspell // matches the upstream API JSON key
	PostalAddress   string `json:"PostalAddress"`
	PostalAddress2  string `json:"PostalAddress2"`
	Suburb          string `json:"Suburb"`
	PostCode        string `json:"PostCode"`
	Province        string `json:"Province"`
	City            string `json:"City"`
	Country         string `json:"Country"`
	PhoneCountry    string `json:"PhoneCountry"`
	PhoneArea       string `json:"PhoneArea"`
	PhoneLocal      string `json:"PhoneLocal"`
	PhoneExtension  string `json:"PhoneExtension"`
	MobileCountry   string `json:"MobileCountry"`
	MobileArea      string `json:"MobileArea"`
	MobileLocal     string `json:"MobileLocal"`
	MobileExtension string `json:"MobileExtension"`
	FaxCountry      string `json:"FaxCountry"`
	FaxArea         string `json:"FaxArea"`
	FaxLocal        string `json:"FaxLocal"`
}

ContactDetail is the full contact record returned by get_contact. Fields are PascalCase JSON keys.

type ContactOptions

type ContactOptions struct {
	ContactID string `url:"contact_id"`
}

ContactOptions identifies a contact by ID.

type ContactSummary

type ContactSummary struct {
	ContactID      string `json:"contact_id"`
	Name           string `json:"name"`
	RegistrantName string `json:"registrant_name"`
	Email          string `json:"email"`
	PhoneCountry   string `json:"phone_cntry"`
	PhoneArea      string `json:"phone_area"`
	PhoneLocal     string `json:"phone_local"`
	PhoneExtension string `json:"phone_extension"`
	DomainCount    Number `json:"domain_count"`
}

ContactSummary is the brief contact entry returned by list_contacts and search_contacts.

DomainCount uses Number because the API returns it as a JSON number for established contacts (`0`) and as a JSON string for newly-created contacts (`"0"`) within the same shape — see the Number type documentation.

type CreateContactOptions

type CreateContactOptions struct {
	Name           string `url:"name"`
	Email          string `url:"email"`
	PostalAddress  string `url:"postal_address"`
	PostalAddress2 string `url:"postal_address2"`
	Suburb         string `url:"suburb"`
	City           string `url:"city"`
	Country        string `url:"country"`
	PostCode       string `url:"params[PostCode]"`
	Province       string `url:"params[Province],omitempty"`
	Organization   string `url:"params[Organization],omitempty"` //nolint:misspell // matches the upstream API wire field name

	// Phone is required. Per the published schema: Country, Area,
	// Local are required; Extension is optional.
	PhoneCountry   string `url:"params[Phone][Country],omitempty"`
	PhoneArea      string `url:"params[Phone][Area],omitempty"`
	PhoneLocal     string `url:"params[Phone][Local],omitempty"`
	PhoneExtension string `url:"params[Phone][Extension],omitempty"`

	// Fax — fully optional. Same Country/Area/Local/Extension shape.
	FaxCountry   string `url:"params[Fax][Country],omitempty"`
	FaxArea      string `url:"params[Fax][Area],omitempty"`
	FaxLocal     string `url:"params[Fax][Local],omitempty"`
	FaxExtension string `url:"params[Fax][Extension],omitempty"`

	// Mobile — fully optional. Same Country/Area/Local/Extension
	// shape. Area on NZ mobiles is the network prefix (e.g. "21").
	MobileCountry   string `url:"params[Mobile][Country],omitempty"`
	MobileArea      string `url:"params[Mobile][Area],omitempty"`
	MobileLocal     string `url:"params[Mobile][Local],omitempty"`
	MobileExtension string `url:"params[Mobile][Extension],omitempty"`
}

CreateContactOptions describes a new domain contact for the Shared Registry System (POST srs/create_contact.json).

Wire schema (per docs.sitehost.nz, May 2026)

The endpoint is form-encoded. Two naming conventions coexist:

  • Top-level (no params[] wrapper): name, email, postal_address, postal_address2, suburb, city, country.
  • params[<PascalCase>] for everything else: PostCode, Province, Organisation (see field name on the struct for the wire key).
  • params[<Group>][<Field>] for the three phone-style numbers: params[Phone][Country|Area|Local|Extension] and identical shapes for Fax and Mobile.

Field-name capitalisation matters. Sub-keys are PascalCase (Country, not country / cntry / CountryCode). Lowercase or abbreviated variants are silently rejected with confusing errors like "phone country code number is missing" or "phone number is missing".

Required vs optional (live finding — diverges from public docs)

Required (server-side validated):

  • Name, Email
  • PostalAddress, PostalAddress2
  • Suburb (live: omitting it returns "The suburb is missing.")
  • City, Country (ISO 2-letter, e.g. "NZ")
  • PostCode (params[PostCode])
  • Phone: Country, Area, Local (Extension optional)

Optional but commonly required by registries:

  • Province, Organisation
  • Fax, Mobile (full sub-arrays)

Email TLD constraint (live finding)

Email must use a real public-suffix TLD (.com, .nz, …). RFC-2606 reserved TLDs (.example, .test, .invalid) are rejected with "Please specify a valid email address." Use example.com, not example.example.

Phone format

Country: digits only, e.g. "64" for NZ. Area: digits only, no leading zero ("9" not "09" — though the API accepts and normalises "09"). Local: line number digits only, no separators. Extension: optional digits.

type CreateContactResponse

type CreateContactResponse struct {
	Return struct {
		ContactID string `json:"ContactID"`
	} `json:"return"`
	models.APIResponse
}

CreateContactResponse returns the new contact's id (and a snapshot of the contact body the registry stored).

The JSON key is "ContactID" (PascalCase) per the live API.

type CreateDomainOptions

type CreateDomainOptions struct {
	Domain            string `url:"domain"`
	Term              int    `url:"term,omitempty"`
	RegistrantContact int    `url:"registrant_contact"`
	AdminContact      int    `url:"params[AdminContact]"`
	TechnicalContact  int    `url:"params[TechContact]"`
	BillingContact    int    `url:"params[BillingContact]"`
	Privacy           string `url:"privacy,omitempty"`
}

CreateDomainOptions describes a new .nz domain to register. Domain and the four contact IDs are required.

API parameter naming is inconsistent here:

  • registrant_contact (no _id, top-level)
  • params[AdminContact] (PascalCase, nested in params)
  • params[TechContact] (note: "Tech", not "Technical")
  • params[BillingContact]

The Go fields use uniform names; tags reflect the wire shape.

type DeleteContactOptions

type DeleteContactOptions struct {
	ContactID int `url:"contact_id"`
}

DeleteContactOptions identifies a contact to remove.

type Domain

type Domain struct {
	ID                     string `json:"domain_id"`
	Domain                 string `json:"domain"`
	State                  string `json:"state"`
	API                    string `json:"api"`
	ClientID               string `json:"client_id"`
	ClientName             string `json:"client_name"`
	Locked                 string `json:"locked"`
	Private                string `json:"private"`
	Pending                string `json:"pending"`
	Premium                string `json:"premium"`
	RegistrantName         string `json:"registrant_name"`
	RegID                  string `json:"reg_id"`
	RegName                string `json:"reg_name"`
	AdmID                  string `json:"adm_id"`
	AdmName                string `json:"adm_name"`
	TecID                  string `json:"tec_id"`
	TecName                string `json:"tec_name"`
	AutoRenewTerm          string `json:"autorenew_term"`
	AutoRenewDaysRemaining string `json:"autorenew_days_remaining"`
	DateRegistered         string `json:"dateregistered"`
	DateModified           string `json:"datemodified"`
	DateBilledUntil        string `json:"datebilleduntil"`
	DateCancelled          string `json:"datecancelled"`
	DateLocked             string `json:"datelocked"`
}

Domain is a single registered-domain entry from list_domains.

String-typed numeric / boolean fields (Locked, Private, Pending, Premium, AutoRenewTerm, AutoRenewDaysRemaining) reflect the API's actual response shape — values arrive as strings ("0", "1", "12") rather than typed numbers / bools. Consumers should convert as needed.

JSON tag casing is inconsistent because the API itself is — some fields use snake_case (client_id, domain_id), others use lowercase-no-underscore (dateregistered, datebilleduntil). Tags reflect what the API returns, not what's stylistically uniform.

type DomainAvailableOptions

type DomainAvailableOptions struct {
	Domain string `url:"domain"`
}

DomainAvailableOptions checks whether a domain is registrable.

type DomainDetail

type DomainDetail struct {
	ClientID               int    `json:"ClientID"`
	Domain                 string `json:"Domain"`
	State                  string `json:"State"`
	RState                 int    `json:"RState"`
	AutorenewReminderSent  bool   `json:"autorenew_reminder_sent"`
	TransferAutorenewSent  bool   `json:"transfer_autorenew_sent"`
	API                    string `json:"API"`
	RegistrantName         string `json:"RegistrantName"`
	DateRegistered         string `json:"DateRegistered"`
	DateModified           string `json:"DateModified"`
	DateBilledUntil        string `json:"DateBilledUntil"`
	DateCancelled          string `json:"DateCancelled"`
	DatePrebilled          string `json:"dateprebilled"`
	DateLocked             string `json:"DateLocked"`
	DateRenewed            string `json:"daterenewed"`
	AutorenewTerm          int    `json:"autorenew_term"`
	AutorenewDaysRemaining int    `json:"autorenew_days_remaining"`
	RegistrantContactID    int    `json:"RegistrantContactID"`
	AdminContactID         int    `json:"AdminContactID"`
	TechnicalContactID     int    `json:"TechnicalContactID"`
	BillingContactID       int    `json:"BillingContactID"`
	Locked                 bool   `json:"Locked"`
	Private                bool   `json:"Private"`
	Pending                bool   `json:"Pending"`
	TransferStatus         string `json:"TransferStatus"`
	TransferID             int    `json:"TransferID"`
	AuthCodeGenerated      string `json:"auth_code_generated"`
	DateAdded              string `json:"date_added"`
	DateUpdated            string `json:"date_updated"`
	Premium                bool   `json:"premium"`
}

DomainDetail is the full per-domain shape returned by get_domain. Fields are PascalCase JSON keys matching the underlying registry schema. RState is a numeric status code; Locked / Private / Pending / Premium are real bools.

type DomainOptions

type DomainOptions struct {
	Domain string `url:"domain"`
}

DomainOptions identifies a single domain — used by get_domain, domain_inside_grace_period, get_domain_price, can_transfer_domain, list_name_servers, and the lifecycle operations (cancel_domain, lock_domain, unlock_domain).

type DomainPrice

type DomainPrice struct {
	DomainPrice        float64 `json:"DomainPrice"`
	TotalPrice         float64 `json:"total_price"`
	TieredPrice        string  `json:"tiered_price"`
	BasePrice          string  `json:"base_price"`
	Premium            bool    `json:"premium"`
	BasePrivacyPrice   string  `json:"base_privacy_price"`
	TieredPrivacyPrice string  `json:"tiered_privacy_price"`
}

DomainPrice describes pricing for a single domain.

type EmailTemplate

type EmailTemplate struct {
	TemplateID    string   `json:"template_id"`
	ClientID      string   `json:"client_id"`
	Type          string   `json:"type"`
	Name          string   `json:"name"`
	Subject       string   `json:"subject"`
	Template      string   `json:"template"`
	DateAdded     string   `json:"date_added"`
	DateUpdated   string   `json:"date_updated"`
	AvailableTags []string `json:"available_tags"`
	RequiredTags  []string `json:"required_tags"`
	Customized    bool     `json:"customized"` //nolint:misspell // matches the upstream API JSON key
}

EmailTemplate is a single registry-email template (renewal reminders, transfer confirmations, etc.).

Field decoding matches the live response from list_email_templates: lowercase `name` is the human-readable label, `type` is the slug used internally, `subject` and `template` are the editable bodies. AvailableTags and RequiredTags list the {PLACEHOLDER} substitutions the registry recognises in this template.

type GetCompanyInfoResponse

type GetCompanyInfoResponse struct {
	Return CompanyInfo `json:"return"`
	models.APIResponse
}

GetCompanyInfoResponse represents the response from get_company_info.

type GetContactResponse

type GetContactResponse struct {
	Return ContactDetail `json:"return"`
	models.APIResponse
}

GetContactResponse represents the response from get_contact.

type GetDomainPriceResponse

type GetDomainPriceResponse struct {
	Return DomainPrice `json:"return"`
	models.APIResponse
}

GetDomainPriceResponse represents the response from get_domain_price.

type GetDomainResponse

type GetDomainResponse struct {
	Return DomainDetail `json:"return"`
	models.APIResponse
}

GetDomainResponse represents the response from get_domain.

type GetEmailTemplateOptions

type GetEmailTemplateOptions struct {
	Template string `url:"template"`
}

GetEmailTemplateOptions identifies a single template to read. Template is the template's name as returned by ListEmailTemplates.

type GetEmailTemplateResponse

type GetEmailTemplateResponse struct {
	Return EmailTemplate `json:"return"`
	models.APIResponse
}

GetEmailTemplateResponse holds a single template body.

type GetPricingTiersResponse

type GetPricingTiersResponse struct {
	Return []PricingTier `json:"return"`
	models.APIResponse
}

GetPricingTiersResponse represents the response from get_pricing_tiers.

type JobResponse

type JobResponse struct {
	Return struct {
		models.Job `json:"job"`
	} `json:"return"`
	models.APIResponse
}

JobResponse is the standard response shape for SRS write operations that queue a scheduler job — create_domain, cancel_domain, etc. (Note: this matches the JobResponse pattern used in other gosh packages, but is package-local to keep srs self-contained.)

type ListContactsResponse

type ListContactsResponse struct {
	models.Pagination
	Return []ContactSummary `json:"return"`
	models.APIResponse
}

ListContactsResponse represents the response from list_contacts. Note: pagination fields are at the top level (not inside Return).

type ListDomainsOptions

type ListDomainsOptions struct {
	SortBy     string `url:"filters[sort_by],omitempty"`
	SortDir    string `url:"filters[sort_dir],omitempty"`
	PageSize   int    `url:"filters[page_size],omitempty"`
	PageNumber int    `url:"filters[page_number],omitempty"`
}

ListDomainsOptions represents optional filters for the list_domains call. SortBy and SortDir control ordering; PageSize and PageNumber control pagination. All fields are optional.

type ListDomainsResponse

type ListDomainsResponse struct {
	Return struct {
		models.Pagination
		Data []Domain `json:"data"`
	} `json:"return"`
	models.APIResponse
}

ListDomainsResponse represents the response from list_domains. The API returns a paginated wrapper around the data array.

type ListEmailTemplatesResponse

type ListEmailTemplatesResponse struct {
	Return []EmailTemplate `json:"return"`
	models.APIResponse
}

ListEmailTemplatesResponse is the response from "srs/list_email_templates.json".

type ListNameServersResponse

type ListNameServersResponse struct {
	Return []NameServer `json:"return"`
	models.APIResponse
}

ListNameServersResponse represents the response from list_name_servers.

type ListValidTLDsResponse

type ListValidTLDsResponse struct {
	Return []TLD `json:"return"`
	models.APIResponse
}

ListValidTLDsResponse represents the response from list_valid_tlds.

type NameServer

type NameServer struct {
	Name     string `json:"name"`
	IPv4Addr string `json:"ipv4addr"`
	IPv6Addr string `json:"ipv6addr"`
}

NameServer is a single nameserver entry.

type NameServerEntry

type NameServerEntry struct {
	Name     string
	IPv4Addr string
	IPv6Addr string
}

NameServerEntry is a single nameserver record to add to a domain via "srs/add_name_servers.json". Name is required; IPv4Addr and IPv6Addr are only required when registering glue records (the nameserver is itself a hostname inside the domain you're updating). For external nameservers (ns1.somewhere-else.com) leave IPv4Addr and IPv6Addr empty.

type NewUDAIOptions

type NewUDAIOptions struct {
	Domain string `url:"domain"`
}

NewUDAIOptions requests a fresh UDAI (transfer authorisation code) for a domain via "srs/new_udai.json".

The UDAI is sent by the registry to the registrant's email on record. This endpoint does not return the code in its response; it triggers the email and returns a {status, msg} envelope.

Use cases:

  • Transferring a .nz domain *out* to another registrar — the gaining registrar needs the UDAI from the registrant.
  • Refreshing a stale or compromised UDAI.

Behaviour is TLD-specific: .nz uses UDAI as its sole transfer- authorisation mechanism (no EPP-style transfer locks); gTLDs (.com, .net) use a different "auth code" concept that may or may not be exposed via this endpoint depending on registrar configuration.

type Number

type Number int64

Number tolerates the SRS API's mixed JSON-string / JSON-number serialisation of numeric fields. ContactSummary.DomainCount is the known case: established contacts return it as a JSON number (`0`), newly-created contacts return it as a JSON string (`"0"`), within the same shape. Mirrors the bandwidth.Number pattern from PR #43.

func (*Number) UnmarshalJSON

func (n *Number) UnmarshalJSON(b []byte) error

UnmarshalJSON accepts either a JSON string or JSON number.

type PricingTier

type PricingTier struct {
	Type     int    `json:"type"`
	TypeName string `json:"type_name"`
	Count    string `json:"count"`
	Price    string `json:"price"`
}

PricingTier describes a single pricing tier (count threshold, price at that tier).

type PrivacyOptions

type PrivacyOptions struct {
	Domain string `url:"domain"`
	Reason string `url:"reason"`
}

PrivacyOptions describes a privacy-protection toggle. Reason is required by the API for both enable and disable; it's recorded at the registrar but is not user-visible.

type RenewDomainOptions

type RenewDomainOptions struct {
	Domain  string `url:"domain"`
	Term    int    `url:"term"`
	Privacy string `url:"options[privacy],omitempty"`
}

RenewDomainOptions extends a domain's registration term.

**This call charges the SiteHost account** at the renewal price for Term months — same pricing matrix as srs.GetDomainPrice with type="renew". There is no dry-run mode. Read GetDomain.BilledUntil before and after to confirm the extension landed.

Term is the renewal length in months (12 = 1 year, 24 = 2 years). Privacy is optional: 1 enables WHOIS privacy at renewal time, 0 disables. Leave empty to keep the current setting.

type SearchContactsOptions

type SearchContactsOptions struct {
	Name           string `url:"query[name],omitempty"`
	Email          string `url:"query[email],omitempty"`
	RegistrantName string `url:"query[registrant_name],omitempty"`
	Offset         int    `url:"offsets[offset],omitempty"`
	Limit          int    `url:"offsets[limit],omitempty"`
}

SearchContactsOptions filters the contact list. At least one of Name, Email, or RegistrantName must be set.

type SearchContactsResponse

type SearchContactsResponse struct {
	Return []ContactSummary `json:"return"`
	models.APIResponse
}

SearchContactsResponse represents the response from search_contacts.

type TLD

type TLD struct {
	TLD         string `json:"tld"`
	Term        string `json:"term"`
	Type        string `json:"type"`
	CanTransfer string `json:"can_transfer"`
	CanProtect  string `json:"can_protect"`
	DateAdded   string `json:"date_added"`
	DateUpdated string `json:"date_updated"`
}

TLD describes a supported TLD's properties.

type TLDsAvailableOptions

type TLDsAvailableOptions struct {
	Domain string `url:"domain"`
}

TLDsAvailableOptions checks domain availability via "srs/domain_tlds_available.json" (GET).

Despite the plural-TLD endpoint name, live behaviour (May 2026) is single-domain: requires a fully-qualified `domain=<label>.<tld>` and returns `{domain, available}` — the same shape as `srs/domain_available.json`. A bare label without TLD is rejected with "Please specify a valid domain name." If a true multi-TLD fan-out parameter exists it isn't documented and we couldn't surface it via probing.

type TLDsAvailableResponse

type TLDsAvailableResponse struct {
	Return TLDsAvailableReturn `json:"return"`
	models.APIResponse
}

TLDsAvailableResponse mirrors the live single-domain payload.

type TLDsAvailableReturn

type TLDsAvailableReturn struct {
	Domain    string `json:"domain"`
	Available bool   `json:"available"`
}

TLDsAvailableReturn is the inner payload — same shape as srs.DomainAvailable.

type TransferDomainOptions

type TransferDomainOptions struct {
	Domain              string
	UDAI                string
	RegistrantContactID int
	AdminContactID      int
	TechnicalContactID  int
	BillingContactID    int
	Term                int
	NameServers         []NameServerEntry
}

TransferDomainOptions submits a domain-transfer-in request via "srs/transfer_domain.json".

**Cost warning:** transfers typically charge a renewal-priced term at the registry and add a year (or `params[term]` months) to the expiry. Confirm pricing via srs.GetDomainPrice with type="transfer" before calling.

Required:

  • Domain — the domain to transfer in.

Conditionally required:

  • UDAI — the registry auth code from the losing registrar. Required for TLDs that use UDAI/auth-code transfers (.nz, gTLDs). Some legacy registries don't require it.

Optional but commonly required by registries:

  • RegistrantContactID, AdminContactID, TechnicalContactID, BillingContactID — defaults to the account's primary contact when omitted, but most registries require an explicit registrant on transfer-in.
  • Term — months. Defaults to the registry minimum (typically 12).
  • NameServers — initial nameserver set. Defaults to the existing set carried over from the losing registrar.

type UpdateAutoRenewOptions

type UpdateAutoRenewOptions struct {
	Domain        string `url:"domain"`
	Term          int    `url:"term"`
	DaysRemaining int    `url:"days_remaining"`
}

UpdateAutoRenewOptions configures the auto-renew schedule for a domain. All four fields are required by the API.

Term is the renewal-period length in months (12 = 1 year, etc.). Set Term to 0 to disable auto-renew (verify by reading srs.GetDomain(domain).AutorenewTerm afterwards — value 0 means disabled).

DaysRemaining controls how many days before expiry the renewal fires (e.g. 30 = renew 30 days before billed-until date).

type UpdateCompanyInfoOptions

type UpdateCompanyInfoOptions struct {
	CompanyName          string `url:"params[CompanyName],omitempty"`
	CompanyURL           string `url:"params[CompanyUrl],omitempty"`
	CompanyRenewURL      string `url:"params[CompanyRenewUrl],omitempty"`
	CompanyEmail         string `url:"params[CompanyEmail],omitempty"`
	CompanyEmailFrom     string `url:"params[CompanyEmailFrom],omitempty"`
	CompanyEmailFromName string `url:"params[CompanyEmailFromName],omitempty"`
	CompanySupportEmail  string `url:"params[CompanySupportEmail],omitempty"`
	CompanyPhone         string `url:"params[CompanyPhone],omitempty"`
	CompanyFax           string `url:"params[CompanyFax],omitempty"`
	// SendRenewedEmail is "1" for yes, "0" for no. Stringified to
	// distinguish "unset" (don't send) from explicit-zero ("0",
	// disable).
	SendRenewedEmail string `url:"params[SendRenewedEmail],omitempty"`
}

UpdateCompanyInfoOptions updates account-level company info (used in registry whois output and renewal email branding). All fields optional — only non-empty fields are sent. Use GetCompanyInfo to read current values before writing.

type UpdateContactOptions

type UpdateContactOptions struct {
	ContactID      int    `url:"contact_id"`
	Name           string `url:"params[Name],omitempty"`
	Email          string `url:"params[Email],omitempty"`
	PostalAddress  string `url:"params[PostalAddress],omitempty"`
	PostalAddress2 string `url:"params[PostalAddress2],omitempty"`
	Suburb         string `url:"params[Suburb],omitempty"`
	City           string `url:"params[City],omitempty"`
	Country        string `url:"params[Country],omitempty"`
	PostCode       string `url:"params[PostCode],omitempty"`
	Province       string `url:"params[Province],omitempty"`
}

UpdateContactOptions edits an existing contact. Only the fields you set are sent (omitempty everywhere). All field names are PascalCase per the API's params[<Name>] convention.

type UpdateDomainContactsOptions

type UpdateDomainContactsOptions struct {
	Domain              string `url:"domain"`
	RegistrantContactID int    `url:"registrant_contact_id"`
	AdminContactID      int    `url:"admin_contact_id"`
	TechnicalContactID  int    `url:"technical_contact_id"`
	BillingContactID    int    `url:"billing_contact_id,omitempty"`
}

UpdateDomainContactsOptions rebinds the four contact roles (registrant / admin / technical / billing) on a domain. All four contact IDs are required by the API except BillingContact per the docs (which marks billing as optional, but in practice most TLDs require it).

type UpdateDomainOptions

type UpdateDomainOptions struct {
	Domain string `url:"domain"`
}

UpdateDomainOptions triggers a domain-record refresh via "srs/update_domain.json".

The public docs only list client_id and domain as parameters; no params[*] block is documented. In practice the endpoint reconciles the local SiteHost record with the registry's view (whois, expiry, contact bindings, nameservers). It does not take new field values — for those use the role-specific endpoints (UpdateDomainContacts, AddNameServers, etc.).

Returns the bare {status, msg} envelope. Re-read with srs.GetDomain afterwards to observe any changes.

type UpdateEmailTemplateOptions

type UpdateEmailTemplateOptions struct {
	Template      string `url:"template"`
	EmailSubject  string `url:"params[EmailSubject],omitempty"`
	EmailTemplate string `url:"params[EmailTemplate],omitempty"`
}

UpdateEmailTemplateOptions edits a single template.

Template is the template name (required). EmailSubject and EmailTemplate are both optional — only set fields are sent. To reset a template to its default, the SiteHost API does not expose a dedicated "reset" verb; capture the defaults first via GetEmailTemplate before editing if a rollback is needed.

**Account-wide impact:** these templates drive customer-facing renewal reminders, transfer notifications, etc. Test changes against a non-production account first.

type ValidateUDAIOptions

type ValidateUDAIOptions struct {
	Domain string `url:"domain"`
	UDAI   string `url:"udai"`
}

ValidateUDAIOptions checks whether a UDAI (auth code) is valid for a domain via "srs/validate_udai.json" (GET). Both fields are required.

Used by the *gaining* registrar before submitting a transfer: validate the code first to catch typos or expired codes before kicking off the registry transfer process.

The public docs do not list a parameter table; the inferred shape is domain=...&udai=.... Validate live before relying on the response shape.

type VerifyEmailTokenOptions

type VerifyEmailTokenOptions struct {
	Token string `url:"token"`
}

VerifyEmailTokenOptions verifies a registrant-email confirmation token via "srs/verify_email_token.json" (GET).

Background: when a contact's email changes (or a new domain is registered), some registries (notably ICANN-governed gTLDs) require the registrant to confirm ownership of the email by clicking a link. The link carries a token; this endpoint marks the token as confirmed.

The public docs do not list parameters; the inferred shape is `?token=...`. Validate live before relying on the response shape.

This endpoint is typically driven by the end-user clicking a link in the verification email rather than called from server code; it's wrapped here for completeness and for any automated re-verification flows.

type Whois

type Whois struct {
	Domain          string            `json:"DomainName"`
	State           string            `json:"Status"`
	DateRegistered  string            `json:"RegisteredDate"`
	DateModified    string            `json:"ModifiedDate"`
	DateBilledUntil string            `json:"BilledUntil"`
	NameServers     []WhoisNameServer `json:"NameServers"`
	Registrant      WhoisContact      `json:"RegistrantContact"`
	Technical       WhoisContact      `json:"TechnicalContact"`
	Admin           WhoisContact      `json:"AdminContact"`
}

Whois is the structured whois result for a domain. Field-name capitalisation in the API is unusual (PascalCase JSON keys), reflecting the underlying registry response shape.

type WhoisContact

type WhoisContact struct {
	Name          string            `json:"Name"`
	Company       string            `json:"Company"`
	Email         string            `json:"Email"`
	PostalAddress map[string]string `json:"PostalAddress"`
}

WhoisContact is a contact block within a whois response. The PostalAddress field is itself a key/value map because the underlying registry returns a variable set of address fields per domain (e.g. {"Country": "NZ"} for some, with Street / City / Postcode for others) — using a map captures whatever the API returns without forcing speculation about field names.

type WhoisNameServer

type WhoisNameServer struct {
	FQDN    string `json:"FQDN"`
	IP4Addr string `json:"IP4Addr"`
	IP6Addr string `json:"IP6Addr"`
}

WhoisNameServer is a name-server entry within a whois response.

type WhoisOptions

type WhoisOptions struct {
	Domain string `url:"domain"`
}

WhoisOptions represents the parameters for a whois lookup. Domain is required.

type WhoisResponse

type WhoisResponse struct {
	Return   Whois  `json:"return"`
	SourceIP string `json:"SourceIP"`
	models.APIResponse
}

WhoisResponse represents the response from the whois endpoint. SourceIP is the address the whois query was sourced from (returned by the API alongside the registry data).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL