HelipodDocs

Errors

Error format, status codes and error codes of the Domain API.

Format

Every error has the same envelope:

{ "success": false, "error": "Domain not found", "code": "NOT_FOUND" }
  • error is a message for humans. Some messages are in Indonesian (for example Saldo tidak cukup or Lengkapi data pemilik domain dulu: ...), and wording can change.
  • code is stable. Build your error handling on it.
  • Some errors add fields, for example missing on REGISTRANT_INCOMPLETE.

Status codes

StatusMeaningCharged?
400The request was understood but refused: unsupported extension or period, premium name, owner details incomplete.No
401Missing, invalid or expired API key.No
402Wallet balance too low for a paid call.No
403The key is not allowed to use the Domain API.No
404Unknown route, the domain does not exist on your account, or an unknown or non-numeric host or price id.No
409The name is taken or already in your account, the domain is waiting for owner details, a renewal is already running, or WHOIS protection is already on.No
422The body or query does not match the schema (VALIDATION_ERROR), or the registry rejected the request (REGISTRAR_REJECTED).Refunded
429Rate limit exceeded. Wait for retry-after seconds.No
500An unexpected error.Refunded
502The registry could not be reached.Refunded

For paid calls, the charge happens only after every check that returns 400, 402, 404 or 409 passes. When the registry then rejects the request (422 REGISTRAR_REJECTED) or cannot be reached (502 REGISTRAR_ERROR), the amount is refunded to your wallet automatically.

Error codes

codeStatusMeaning and what to do
NO_API_KEY401Send Authorization: Bearer hel_your_key.
INVALID_API_KEY401The key is unknown or revoked, or the account is inactive. Create a new key.
API_KEY_EXPIRED401The key passed its expiry date. Create a new key.
SCOPE_NOT_ALLOWED403The key does not have the Domain API product. Create a key with Domain API enabled.
ACCOUNT_KEY_REQUIRED403The key is limited to one project. Domains belong to the account: create a key with Whole account access.
TLD_NOT_SUPPORTED400The extension cannot be registered or transferred through Helipod, or has no price. See Supported extensions.
PERIOD_NOT_SUPPORTED400period is not 1. Transfers and renewals are for one year.
PRICE_UNAVAILABLE400No valid price exists for this extension right now. Try again later or contact support.
PREMIUM_NOT_SUPPORTED400Premium names cannot be registered online. Contact support for a quote.
REGISTRANT_INCOMPLETE400Owner details are missing. missing lists the fields. Complete them with PATCH /domains/registrant or in the dashboard. See Owner details.
INVALID_REGISTRANT400An owner detail sent to PATCH /domains/registrant was refused. error says which.
DOMAIN_NOT_LINKED400The domain is not active at the registry yet, so it cannot be renewed.
INSUFFICIENT_BALANCE402The wallet cannot cover the price. Top up and retry.
DOMAIN_NOT_FOUND404The domain id does not exist, is not a number, belongs to another account, or the domain is not registered at the registry yet.
NOT_FOUND404The route does not exist, a host or price id is unknown or not a number, or the registry does not know the requested item.
DOMAIN_UNAVAILABLE409The name belongs to another account. Nothing was charged.
DOMAIN_ALREADY_IN_ACCOUNT409The name is already in your account. Nothing was charged.
DOMAIN_PENDING_PROFILE409The domain is a free domain waiting for owner details. Activate it in the dashboard. See Pending profile domains.
RENEW_IN_PROGRESS409The domain is already being renewed (by another call or by auto-renew). Read it again in a moment.
WHOIS_PROTECTION_ACTIVE409WHOIS protection is already on. Nothing was charged.
VALIDATION_ERROR422A required field is missing or has the wrong type or value.
REGISTRAR_REJECTED422The registry rejected the request: name not available, wrong auth code, invalid record, unknown host. error gives the reason when it can be shown. Fix the input; the charge, if any, was refunded.
RATE_LIMITED429More than 10 requests per second with this key. Back off and retry.
INTERNAL_ERROR500Unexpected error. Retry later; contact support if it persists.
REGISTRAR_ERROR502The registry could not be reached. The message is generic. Retry later; the charge, if any, was refunded.
REQUEST_ERROR4xxA refused request whose detail cannot be shown.

Another account's domain and a malformed id both return 404, never 403, so the API does not reveal which domain ids exist.

Delivered but not yet recorded

In rare cases the registry completes a registration, transfer or renewal but Helipod cannot record it right away. The call still succeeds, because the domain was delivered and paid for, and nothing is refunded:

Response (201)
{
  "success": true,
  "code": "DOMAIN_SAVE_PENDING",
  "message": "example.com is done, but it does not show in your dashboard yet. Please contact support and we will add it for you.",
  "data": { "name": "example.com", "status": 1, "status_label": "Active" },
  "billing": { "registration": 199000, "whoisProtection": 0, "total": 199000, "depositCharged": 199000 }
}

A register or transfer answers 201, a renewal 200. When code is DOMAIN_SAVE_PENDING, contact support and do not retry the call: a retry would charge you again.

Example: handling errors

async function domainApi(path, init = {}) {
  const res = await fetch(`https://api.helipod.io/api${path}`, {
    ...init,
    headers: {
      Authorization: "Bearer hel_your_key",
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  const body = await res.json();
  if (body.success) {
    if (body.code === "DOMAIN_SAVE_PENDING") console.warn(body.message); // delivered: contact support, do not retry
    return body;
  }

  if (res.status === 429) {
    const wait = Number(res.headers.get("retry-after") ?? 1);
    throw new Error(`Rate limited, retry in ${wait}s`);
  }
  if (body.code === "REGISTRANT_INCOMPLETE") {
    throw new Error(`Complete owner details first: ${body.missing.join(", ")}`);
  }
  if (body.code === "INSUFFICIENT_BALANCE") throw new Error("Top up your wallet");
  throw new Error(`${res.status} ${body.code ?? "ERROR"}: ${body.error}`);
}

On this page