Docs API

Domains, DNS and accounts

Manage domains and their DNS zones, registrar settings, email forwarding and Mailgun sending, plus accounts, users, invites and billing.

Domains and accounts are the two halves of the customer-facing side of CaptainCore. A domain row can carry a DNS zone at Constellix, a registrar connection, forwarding through Forward Email and a sending subdomain at Mailgun. An account owns sites, domains and a billing relationship.

Note the two prefixes. /domains handles the collection. /domain/{id} handles one domain’s features. That split is historical and both are current.

Domains

Method Path Notes
GET /domains/ Every domain you can access
GET /domain/{domain_id} One domain with registrar, DNS and sending state
POST /domains Create. name is the apex. site_id is required for non-admins and decides the owning account. create_dns_zone defaults to true.
DELETE /domains/{domain_id} Delete, and remove the zone
PUT /domains/{domain_id}/account Reassign to an account (administrator)
POST /domain/{domain_id}/update-site-link Point the domain at a site, site_id
curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{"name":"example.com","site_id":135,"create_dns_zone":false}' \
  https://your-manager.example.com/wp-json/captaincore/v1/domains

The identifiers matter here. domain_id is the CaptainCore row, used on /domain/{id} and /dns/{id}. remote_id is the Constellix zone id, empty when the domain has no zone. provider_id is the registrar connection, empty when the domain is registered elsewhere.

DNS records

DNS is backed by Constellix. Record write routes carry their own permission closure that verifies you can reach the domain and returns 403 token_invalid otherwise.

Method Path Notes
GET /dns/{domain_id} All records in the zone
POST /dns/{domain_id}/records Create a record
PUT /dns/{domain_id}/records/{record_id} Update one
DELETE /dns/{domain_id}/records/{record_id} Delete one
POST /dns/{remote_id}/bulk record_updates array, one object per change
GET /domains/{domain_id}/zone Export the zone file
POST /domains/import Parse and import BIND zone text
POST /domain/{domain_id}/activate-dns-zone Create or link a zone
DELETE /domain/{domain_id}/dns-zone Remove the zone

Create takes type (A, AAAA, ANAME, CNAME, TXT, SPF, MX, SRV, HTTP), name (relative host, empty string for the apex), value and ttl in seconds, defaulting to 3600 if omitted.

curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{"type":"TXT","name":"","value":"v=spf1 include:mailgun.org ~all","ttl":3600}' \
  https://your-manager.example.com/wp-json/captaincore/v1/dns/42/records

POST /domains/import takes zone (the BIND text) and optionally domain, which is overridden if the zone declares $ORIGIN.

Every create, update and delete on a record writes an activity log row with the record type and name.

Registrar actions

Available when the domain has a registrar provider connected, currently Hover.com or Spaceship.

Method Path Notes
GET /domain/{domain_id}/lock_on, /lock_off Transfer lock
GET /domain/{domain_id}/privacy_on, /privacy_off WHOIS privacy
GET /domain/{domain_id}/auth_code Retrieve the transfer auth code
POST /domain/{domain_id}/contacts contacts object with owner, admin, tech, billing
POST /domain/{domain_id}/nameservers Set nameservers

Email forwarding

Forwarding runs through Forward Email. Activation writes the MX and TXT records into the zone.

Method Path Notes
POST /domain/{domain_id}/activate-forward-email If apex MX records already exist the first call returns 409 mx_conflict; retry with overwrite_mx: true
GET /domain/{domain_id}/email-forwards List aliases
POST /domain/{domain_id}/email-forwards name (local part, or * / empty for catch-all) and recipients
PUT /domain/{domain_id}/email-forwards/{alias_id} Update an alias
DELETE /domain/{domain_id}/email-forwards/{alias_id} Remove an alias
GET /domain/{domain_id}/email-forwarding/status Current state, verify=1 runs a verification pass first
GET /domain/{domain_id}/email-forwarding/logs Delivery logs, filtered by event and paged with page_url
DELETE /domain/{domain_id}/email-forwarding Tear it all down (administrator)

recipients accepts a comma-separated string, an array of strings, or an array of {address} objects.

Sending through Mailgun

Mailgun handles outbound mail for a site, on a subdomain such as mg.example.com.

Method Path Notes
GET /domain/{domain_id}/mailgun Current sending configuration
POST /domain/{domain_id}/mailgun/setup domain is the full Mailgun hostname
POST /domain/{domain_id}/mailgun/verify Re-check the DNS records
POST /domain/{domain_id}/mailgun/deploy site_id and from_name required, plus optional environment
DELETE /domain/{domain_id}/mailgun Remove the sending domain
GET /domain/{domain_id}/mailgun/events Recent events
GET /sites/{site_id}/mailgun-events The same feed, keyed by site
GET /domain/{domain_id}/mailgun/usage period is day (30 days), month (12 months) or year (24 months by calendar year)
GET, DELETE /domain/{domain_id}/mailgun/suppressions/{type} Bounces, complaints, unsubscribes
PUT /sites/{site_id}/mailgun Set the sending domain on a site (administrator)

Accounts

Membership levels decide what a user sees inside an account.

Level Sites Domains Billing Reports Manage users
full-billing (owner) yes yes manage manage yes
full yes yes view send no
sites-only yes no no no no
domains-only no yes no no no
Method Path Notes
GET /accounts/ Accounts you belong to
GET /accounts/{account_id} One account
POST /accounts/ Create (administrator), name required
PUT /accounts/{account_id} Update account.name and account.billing_user_id
DELETE /accounts/{account_id} Delete (administrator)
PUT /accounts/{account_id}/plan Change the plan (administrator)
PUT /accounts/{account_id}/defaults Per-account site defaults: email, timezone, recipes, users
POST /site-accounts Attach sites to accounts (administrator)

Users and invites

Method Path Notes
GET /users/ Users you can see
GET /users/{id}/accounts Accounts a user belongs to
POST /users Create (administrator)
GET, PUT /users/{id} Read and update (administrator)
GET /me/ The current user
PUT /me/profile Update your own profile
POST /accounts/{account_id}/invites invite is the email, level defaults to full. You cannot invite as full-billing.
DELETE /accounts/{account_id}/invites/{invite_id} Withdraw an invite
DELETE /accounts/{account_id}/users/{user_id} Remove a member
PUT /accounts/{account_id}/users/{user_id}/level level is one of the four values above
GET /invites Verify an invite, query account and token
POST /invites/accept Accept, same two fields in the body
curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{"invite":"[email protected]","level":"sites-only"}' \
  https://your-manager.example.com/wp-json/captaincore/v1/accounts/12/invites

Two-factor and session routes sit alongside these: POST /me/tfa_activate, /me/tfa_validate, /me/tfa_deactivate, and GET / DELETE /sessions.

Billing, invoices and payment methods

Billing is backed by WooCommerce subscriptions and Stripe.

Method Path Notes
GET /billing/ Billing profile, methods and open invoices
PUT /billing/update Update the billing address
POST /billing/pay-invoice value is the WooCommerce order id, plus either payment_id (saved method or ach_...) or source_id (new Stripe card)
POST /billing/payment-methods Add a card, source_id
PUT /billing/payment-methods/{id}/primary Set the default
DELETE /billing/payment-methods/{id} Remove one
POST /billing/cancel-plan Request cancellation
POST /billing/request-plan-changes Request a plan change
GET /subscriptions/, /subscriptions/{id} Subscriptions
GET /upcoming_subscriptions/ Renewals coming up
GET /invoices/{id} One invoice
GET /invoices/{id}/pdf Invoice PDF

ACH bank payments have their own flow: POST /billing/ach/setup-intent creates a Stripe SetupIntent, POST /billing/ach/payment-method attaches the result, and POST /billing/ach/verify confirms micro-deposits. Administrators can review pending verifications with GET /billing/ach/pending and clear them with POST /billing/ach/admin-verify.

Site requests

Customers can ask for a site rather than create one directly.

Method Path Notes
POST /site-requests Start a request, request.name and request.account_id
GET /site-requests Your requests
POST /site-requests/continue, /site-requests/back Move through the wizard
PUT /site-requests/update Save the current step
POST /site-requests/delete Discard
GET /requested-sites Requests awaiting provisioning