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 |