# Handle errors (https://developer.godaddy.com/en/docs/api-users/errors)

---
title: Handle errors
description: 'Error response shape, status code semantics, and retry guidance.'
keywords: >-
  400 401 403 404 422 429 500, UNABLE_TO_AUTHENTICATE, requestId, error
  envelope, exponential backoff, idempotency key
agentNotes:
  scopes:
    - Any — applies to all API operations
  rateLimit: N/A (informational reference)
  failureRecovery: >-
    Match the 'code' field, not HTTP status, for programmatic handling. 4xx
    errors are client-fixable (check input, scopes, payment profile). 5xx errors
    are safe to retry with exponential backoff. 429 means wait for Retry-After
    header.
related:
  guides:
    - title: Handle rate limits
      href: /docs/api-users/rate-limits
    - title: Authentication
      href: /docs/api-users/auth
    - title: Set up a payment profile
      href: /docs/api-users/payment-profile
    - title: About the Shopping API
      href: /docs/api-users/shopping
  apis:
    - title: Domains v3 reference
      href: /docs/references/rest/domains/v3
    - title: Domains v1 reference
      href: /docs/references/rest/domains/v1
    - title: Hosting API reference
      href: /docs/references/rest/hosting
---

## Overview

GoDaddy REST APIs return a consistent error envelope. Every error response includes a stable `code` field for programmatic handling, and optionally field-level validation details. This page covers the response shape, status code semantics, and retry guidance for GoDaddy REST APIs — including the Domains, Auctions, and Hosting APIs.

The Shopping API does not follow this standard error model. Go to [Shopping API error responses](#shopping-api-error-responses) for its behavior.

## Error response shape

`Error` schema (used for 4xx and 5xx responses):

```json
{
  "code": "INVALID_BODY",
  "message": "Request body did not match the expected schema.",
  "fields": [
    {
      "path": "contactRegistrant.email",
      "code": "INVALID_FORMAT",
      "message": "Value must be a valid email address."
    }
  ]
}
```

| Field      | Required | Description                                                                                                                                             |
| ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`     | Yes      | Stable, machine-readable error code. Match on this for programmatic handling.                                                                           |
| `message`  | No       | Human-readable message. It might change between releases.                                                                                               |
| `fields[]` | No       | Per-field validation details when the error is body- or query-scoped. Each entry has its own `path` (JSONPath into the request), `code`, and `message`. |

`ErrorLimit` extends `Error` with one additional field for rate-limit (`429`) responses:

| Field           | Required | Description                                                                                                       |
| --------------- | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `retryAfterSec` | Yes      | Seconds the caller should wait before retrying the same operation. Mirrored in the `Retry-After` response header. |

## Status codes

| Status                     | Meaning                                                                                                                                          | Caller action                                                                                                                           |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`          | Request was malformed (missing required field, invalid query parameter format).                                                                  | Fix the request. Inspect `fields[]` for specifics.                                                                                      |
| `401 Unauthorized`         | `Authorization` header missing, malformed, expired, or revoked.                                                                                  | Re-authenticate. See [Authentication](https://developer.godaddy.com/docs/api-users/auth).                                                                            |
| `403 Forbidden`            | Authenticated but unauthorized — usually a missing scope or insufficient role.                                                                   | Issue a token with the required scope, or escalate the calling principal's authorization.                                               |
| `404 Not Found`            | The path doesn't exist, or the addressed resource (domain, contact, record) isn't visible to this caller.                                        | Verify the path and confirm the caller owns or can access the resource.                                                                 |
| `409 Conflict`             | The request conflicts with current state (e.g. registering a name already taken; updating a record set that's mid-transfer).                     | Re-read state and retry only after resolving the conflict.                                                                              |
| `422 Unprocessable Entity` | Request was syntactically valid but semantically rejected (e.g. invalid registrant data, TLD-specific constraint failure, `NO_PAYMENT_PROFILE`). | Inspect `code` and `fields[]`. For missing billing, see [Set up a payment profile](https://developer.godaddy.com/docs/api-users/payment-profile).                    |
| `429 Too Many Requests`    | Rate limit exceeded. Domains and Auctions shape the response as `ErrorLimit`.                                                                    | Wait the seconds given by the `Retry-After` header, then retry. Go to [Handle rate limits](https://developer.godaddy.com/docs/api-users/rate-limits) for strategies. |
| `5xx Server Error`         | Upstream registry or service issue.                                                                                                              | Retry idempotent operations with exponential backoff. See [Retry semantics](#retry-semantics) for non-idempotent ones.                  |

## Retry semantics

The following sections describe the retry semantics for read and write operations using Domains API endpoints. The same retry semantics apply across GoDaddy REST APIs. Endpoint paths will vary by API.

### Read operations

All `GET` operations are safe to retry. Domains API examples:

* `GET /v3/domains/check-availability` — availability check
* `GET /v1/domains` — list your domains
* `GET /v1/domains/{domain}` — domain detail
* `GET /v1/domains/{domain}/records` — DNS records

### Write operations

Most Domains writes can be retried after a 5xx, but **the Domains API doesn't support an `Idempotency-Key` request header** — neither v1 nor v2 specs declare one. This affects retry strategy on a few specific operations:

| Operation                                           | Retry-safe?                                                                                                                                                                                                                                                       |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /v1/domains/purchase`                         | **Not idempotent without external coordination.** A retry can result in a duplicate registration if the first attempt actually succeeded server-side. Pair every retry with a fresh `GET /v1/domains/available` and a state check via `GET /v1/domains/{domain}`. |
| `POST /v1/domains/{domain}/renew`                   | Idempotent within a billing cycle in practice — the registry rejects duplicates — but treat the same as `purchase`: confirm state before retrying.                                                                                                                |
| `POST /v1/domains/{domain}/transfer`                | Same as `purchase`.                                                                                                                                                                                                                                               |
| `PUT /v1/domains/{domain}/records` (replace)        | Idempotent by shape — replaying the same request produces the same record set.                                                                                                                                                                                    |
| `PATCH /v1/domains/{domain}/records` (add)          | **Not idempotent** — repeated calls add duplicate records.                                                                                                                                                                                                        |
| `DELETE /v1/domains/{domain}/records/{type}/{name}` | Idempotent — deleting an already-deleted record is a no-op.                                                                                                                                                                                                       |

### Async write operations

The Hosting API returns `202 Accepted` for most write operations. The caller must poll a status endpoint until the operation reaches a terminal state. Retry semantics differ from synchronous writes:

| Operation                        | Idempotent?                                                           | Terminal states       | Retry guidance                                                                                                 |
| -------------------------------- | --------------------------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------- |
| `POST /v1/hosting/apps`          | No — each call creates a new app                                      | `COMPLETED`, `FAILED` | On 5xx or network failure, check `GET /apps` before retrying — a partial success may have provisioned the app. |
| `POST /apps/{appId}/imports`     | Yes — each upload overwrites the preview variant                      | `COMPLETED`, `FAILED` | Safe to retry. The latest upload always wins.                                                                  |
| `POST /apps/{appId}/deployments` | Yes within the same source — republishing the same preview is a no-op | `COMPLETED`, `FAILED` | Safe to retry. If status stays `FAILED`, fetch build logs before retrying.                                     |

## Programmatic error handling

Match on `code`, not `message`. Codes are stable across releases; messages might be refined. The codes below are specific to the Domains API.

Check your API's OpenAPI specification for its error codes.

```js
const res = await fetch(url, { headers });
if (!res.ok) {
  const err = await res.json();
  switch (err.code) {
    case "DOMAIN_NOT_AVAILABLE":
      // someone else registered the name first
      break;
    case "BILLING_DECLINED":
      // payment method failed — surface to user
      break;
    case "NO_PAYMENT_PROFILE":
      // no billing method on account — see payment profile setup
      break;
    default:
      // log err.code and err.fields for debugging
      throw new Error(err.code + ": " + err.message);
  }
}
```

Reference: the `Error` and `ErrorLimit` schemas are defined in the OpenAPI specification.

## Shopping API error responses

The Shopping API usually maps errors to HTTP status codes. A `2xx` response can also contain an error envelope, so check the status and `messages[].code` on every response.

```json
{
  "ucp": { "version": "2026-04-08", "status": "error" },
  "messages": [
    {
      "type": "error",
      "code": "validation_error",
      "content_type": "plain",
      "content": "line_items[0].item.id is required."
    }
  ]
}
```

| Field                | Description                                                                       |
| -------------------- | --------------------------------------------------------------------------------- |
| `ucp.status`         | `"error"` when the request failed. Successful responses can omit this field.      |
| `messages[].code`    | Stable, machine-readable error code. Match on this programmatically.              |
| `messages[].content` | Human-readable description. It might change between releases; do not match on it. |

Common codes include `invalid_request`, `validation_error`, `product_not_found`, `checkout_not_found`, `order_not_found`, `item_not_found`, and `unsupported_currency`.

```js
const res = await fetch(url, { headers });
const body = await res.json();

// Check the HTTP status and the error marker.
if (!res.ok || body?.ucp?.status === "error") {
  const code = body?.messages?.[0]?.code;
  switch (code) {
    case "validation_error":
      // fix the line item and retry
      break;
    case "item_not_found":
      // choose a current purchasable variant
      break;
    default:
      throw new Error(`Shopping API error: ${code}`);
  }
}
```

Go to [About the Shopping API](https://developer.godaddy.com/docs/api-users/shopping#error-responses) for the Shopping status and code reference.
