EngineeringCategory

Introducing the Email API: From a Domain to a Working Mailbox in Three Calls

•14 min read
Felix Gorodishter

Key takeaways

  • The Email API on the GoDaddy Developer Platform lets you create and manage GoDaddy Business Email mailboxes over REST or the gddy CLI, using the same Personal Access Tokens you already use for domains and hosting. Creating a mailbox also sets up the domain's MX, SPF, DKIM, and DMARC records.
  • Mailbox creation is a three-step flow (check eligibility, create, poll), and the eligibility check tells you up front which email plan to use, what might block the address, and whether any agreements apply.
  • Scopes keep each step separate: email.mailbox:read and email.mailbox:create for mailboxes, and a separate shopping.* family for buying an email plan. An agent can prepare the whole job while a person approves the purchase, holds the permission to create, and receives the mailbox password by email.

Introduction

Over the past few months, the GoDaddy Developer Platform has picked up the pieces you need to put a project on the internet. In July, domains gave you a name you could search, register, and point with API calls. Last week, Node.js hosting gave that name something to point at.

That still leaves a piece most businesses want early: an email address on the domain. hello@example.com is often one of the first things someone sets up after registering a name, and until now, setting it up meant leaving your terminal for a dashboard.

Today we're adding email to the platform. The Email API lets you check whether an address can be created, provision a GoDaddy Business Email mailbox, and track it until it's ready to use. Provisioning also sets up the DNS records that email depends on, so there's no separate step to wire up mail routing. If you don't have an email plan yet, the Shopping API sells you one from the same CLI. It all runs over REST with the same Personal Access Tokens and the same gddy CLI you already use for domains and hosting.

The mailbox loop, from the CLI

Here's hello@example.com going from an idea to a working mailbox:

# No email plan yet? Find one and buy it with the Shopping API.
# These commands need shopping scopes, separate from the email ones (see below).
gddy shopping catalog search --category email --currency USD
gddy shopping checkout create --item titanemail-pro:1yr --currency USD

# Review the total and the required agreements before you agree.
# --agree accepts every one of them and charges your saved payment method.
gddy shopping checkout get $CHECKOUT_ID
gddy shopping checkout complete $CHECKOUT_ID --agree

# Can this address exist, and which email plan can hold it?
gddy email check-eligibility --email hello@example.com

# Create it under the plan the check returned.
gddy email create --email hello@example.com \
  --account-id $ACCOUNT_ID \
  --first-name Jane --last-name Smith

# Creation is async. Poll until status is COMPLETED or FAILED.
gddy email get $MAILBOX_ID

# List everything you have.
gddy email list --status COMPLETED

Each command maps to a documented REST endpoint, under /v1/email for mailboxes and /v1/shopping for the purchase, so the same sequence works from your own code, a CI job, or an agent's tool calls. The CLI also carries its own documentation: gddy guide email prints a guide to the whole flow, including every failure reason and what to do about it, and gddy auth scopes --command "email create" tells you which scope a command needs before you run it.

What we built

The Email API has four endpoints and two scopes.

Eligibility before creation. GET /v1/email/check-mailbox-eligibility?email=... answers three questions in one call: can this address exist, which of your email plans can hold it, and whether that plan has any agreements to accept first. The next section covers why this call comes first.

Asynchronous provisioning. POST /v1/email/mailboxes responds 202 Accepted right away, with the new mailbox at status: EXECUTING and a Location header pointing at it. Provisioning continues in the background. Poll GET /v1/email/mailboxes/ every two to four seconds (and no faster than once per second) until it reaches COMPLETED, at which point the mailbox is ready to use, or FAILED. FAILED is terminal: there's no automatic retry, so resubmit the create if it still makes sense.

No passwords in the API. Nothing in a request or response carries a mailbox credential. After the mailbox is created, GoDaddy emails a temporary password to the owner of the GoDaddy account, who uses it to sign in for the first time.

Idempotent creates. POST /v1/email/mailboxes requires an Idempotency-Key header. If a request times out and you retry with the same key, you get the original response back instead of a second mailbox.

Scoped tokens. email.mailbox:read covers the eligibility check, listing, and lookups. email.mailbox:create provisions mailboxes. A script that audits which addresses exist never needs the ability to create one.

Paged listing. GET /v1/email/mailboxes returns every mailbox on domains you own, filterable by status, paged up to 100 at a time, with field selection through field and optional totals through totalRequired.

Errors you can branch on. Eligibility and create failures return 422 with a details[] array. Each entry carries a stable issue code such as EMAIL_PLAN_NOT_AVAILABLE or EMAIL_ADDRESS_ALREADY_EXISTS, plus a human-readable description. Match on issue, not the description.

Why eligibility comes first

Start with the domain. Today, the domain's registration and its DNS zone both have to be with GoDaddy, in the same customer account the token belongs to. That requirement is what lets provisioning write the domain's email DNS records for you (more on that later), and there's no separate step to link the domain first.

A mailbox doesn't exist on its own, either. It's created inside an email plan you already hold, and the API calls that plan an account. You might have zero, one, or several accounts that could take a new address (for example, if you've bought more than one email plan), so before anything gets created, something has to decide which one to use.

The eligibility check makes that decision visible:

{
  "isEligible": true,
  "eligibleAccounts": [
    {
      "accountId": "00000000-0000-0000-0000-000000000001",
      "mailboxType": "TITAN",
      "accountName": "Professional Email Pro Plus",
      "default": true,
      "requirements": []
    }
  ]
}

The account marked default: true is the recommended choice when you have no other preference, and the CLI uses it automatically when it's the only eligible account, so --account-id becomes optional. You don't pick the underlying mail platform either. mailboxType is derived from what the account already holds.

When an address can't be provisioned, the check tells you why, and each reason points to a different next step:

issueWhat it meansWhat to do
EMAIL_PLAN_NOT_AVAILABLEThere's no active email plan for this domain.Buy one with the Shopping API (see the next section), then retry.
EMAIL_ADDRESS_ALREADY_EXISTSThe address is taken.Choose a different username.
EMAIL_ADDRESS_INVALIDThe username fails format or length rules.Fix the address and check again.
DOMAIN_IN_OTHER_EMAIL_PROVIDERThe domain's email runs through another provider.Nothing to do through the API.
EMAIL_PLAN_NOT_ELIGIBLE, DOMAIN_NOT_ELIGIBLEThe plan or domain doesn't support API provisioning.Create the mailbox in the GoDaddy Email dashboard.

The username is validated as part of the check, so a malformed address comes back as EMAIL_ADDRESS_INVALID before anything is created.

The create call re-runs the eligibility check internally, so it can still return a 422 even after a successful check if the domain's state changed in between. That's the classic time-of-check to time-of-use gap, and the API closes it on the server instead of trusting the client's earlier answer. Treat check-eligibility as a preflight that tells you what to send, not a reservation on the address.

No plan yet? Buy one with the Shopping API

Provisioning draws on an email plan the account already holds, so EMAIL_PLAN_NOT_AVAILABLE has no fix inside the email commands. The fix is a purchase, and purchases run through the platform's Shopping API.

Buying needs its own scopes. The email.mailbox:* scopes don't cover shopping, so a token minted only for email can't search the catalog or check out. Searching needs shopping.catalog:read, checking out needs shopping.checkout:execute, and reading the resulting order needs shopping.order:read. In the CLI, step up with gddy auth login --scope shopping.catalog:read --scope shopping.checkout:execute.

The purchase itself is three commands:

  1. gddy shopping catalog search --category email --currency USD lists the email plans you can buy, each with a purchase option ID that combines the product and the term, such as titanemail-pro:1yr. Run the search for the current list rather than hard-coding an ID.
  2. gddy shopping checkout create --item <PURCHASE_OPTION_ID> --currency USD opens a checkout session. It doesn't place an order. Append =QUANTITY to the ID to buy more than one.
  3. gddy shopping checkout complete <CHECKOUT_ID> --agree places the order.

That last step deserves care. --agree accepts every agreement the checkout requires and charges the account's saved payment method, so check the total and the agreements with gddy shopping checkout get <CHECKOUT_ID> before you pass it. Checkout can't add a payment method, either. If the account doesn't have one saved, set up a payment profile first.

After the order completes, the new plan shows up as an eligible account on gddy email check-eligibility, and you can create mailboxes under it.

Agreements are data, not a checkbox

For most accounts, requirements comes back empty, and the create call is just the address, the account, and a display name:

curl -s -X POST "https://api.godaddy.com/v1/email/mailboxes" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "emailAddress": "hello@example.com",
    "accountId": "00000000-0000-0000-0000-000000000001",
    "firstName": "Jane",
    "lastName": "Smith"
  }'

Some plans do carry agreements the customer has to accept before a mailbox can be created. Rather than burying those in a UI, the eligibility check returns each one as a structured object: a type your code can pass back, a title, and a reference to the terms the customer is agreeing to. Pass each accepted type back in a consents array on the create call (--consent in the CLI, repeated once per type), and the 202 response echoes them in an agreements array, so the record of what was accepted lives on the mailbox itself.

If a required agreement is missing, the create fails with CONSENT_NOT_PROVIDED, and the description names the type you left out. Re-run the eligibility check to get the current list and resubmit. Don't hard-code requirement types, because the set can change. Loop over requirements[], show each reference to the person who owns the account, and send back only the types they accepted.

Like domain registration, the mailbox request has no payment fields. The mailbox is created under an email plan you already hold, identified by accountId.

Agents as first-class users

Hand a coding agent a brief: "set up hello@ and jane@ for the new domain." With a token scoped to email.mailbox:read, it can check eligibility for both addresses, report which email plan each one would land on, and surface any requirements, all before anything is created. If an address is taken or the domain has no plan, the issue code tells the agent which of those it's dealing with, so it can suggest a different username or go find a plan instead of guessing.

Buying that plan is the one step that spends money, and it gets the same treatment as a domain purchase. With shopping.catalog:read, the agent can search the catalog and tell you which plan fits. Completing a checkout is a different matter: --agree accepts every required agreement and charges your payment method, and a request to buy isn't the same as agreeing to the terms. The agent shows you the total and each agreement from checkout get and waits for an explicit yes. If you'd rather not rely on that, leave shopping.checkout:execute off the agent's token and run the checkout yourself.

If a plan carries agreements, that's where the agent stops and asks. It shows you each reference verbatim and waits for your approval. Then it creates the mailboxes with a token that holds email.mailbox:create. It generates a separate Idempotency-Key for each address, so a retry after a timeout doesn't produce a duplicate, then polls each mailbox until it reaches a terminal state. It never needs a DNS token, because creating the mailbox sets up the MX, SPF, DKIM, and DMARC records. And it never handles a mailbox password: those go by email to you, the account owner, not back through the API.

As with domains and hosting, the token enforces the boundary, not a prompt. An agent that only needs to read mailbox state never gets the scope to create one. And the agent learns the flow from the same places you do: the markdown docs on the developer portal and the output of gddy guide email in its own terminal.

A domain, an app, and a mailbox

With this launch, three things many projects need early run on one credential model and one CLI: register a name with the Domains API, publish an app with the Node.js Hosting API, and create the address people will write to with the Email API.

The step you might expect to come next, wiring up DNS so mail actually arrives, isn't there. Because the domain and its DNS zone are already in your GoDaddy account, creating a mailbox sets up the domain's email DNS records for you: MX, so other servers know where to deliver mail, SPF and DKIM, so receiving servers can verify that mail from your domain is really yours, and DMARC, which tells them what to do when a message fails those checks. Nobody has to look up record values, and the caller doesn't need a DNS scope to get working mail. The gddy dns commands from the domains launch are for the records you choose to manage, not the ones email requires.

Each product has its own scopes, so you can hand a CI job DNS access, an agent hosting upload access, and keep mailbox creation and checkout for yourself, all from the same Personal Access Tokens page.

Talk to the team

The team that built the Email API and the gddy email commands is working directly with early users, and we're in Discord answering questions ourselves. If something gets in your way, or you need something that isn't there yet, tell us.

What comes next

Today the Email API covers creating mailboxes and reading them back. The next work is the rest of the mailbox lifecycle, so the changes you'd make to an address after it exists are API calls too.

See it in action and try it out

About the Email API covers mailboxes, accounts, and consents, and the Provision a mailbox guide walks the whole flow in curl. CLI setup gets you gddy, and the API reference has every endpoint. If you need a plan first, Create a checkout and place an order covers the Shopping API flow. Generate a token on the Personal Access Tokens page with email.mailbox:read and, when you're ready to create, email.mailbox:create. Add shopping.catalog:read and shopping.checkout:execute if you're buying a plan. Watch an end-to-end demo of the API in action on YouTube.

Create a mailbox and tell us about your experience in Discord. Your feedback is what shapes where this goes next.

We can't wait to see what you build.