Every EPP Status Code, Explained (With Real Lookups)
July 9, 2026
Look up google.com and you get six status codes:
"status": [
"client delete prohibited", "client transfer prohibited", "client update prohibited",
"server delete prohibited", "server transfer prohibited", "server update prohibited"
]
Look up a domain in the last days of its life and you get one:
"status": ["pending delete"]
Nearly every domain lookup returns at least one of these codes (a few registries omit the field entirely), and they are the closest thing the domain system has to a health report: who can modify the domain, whether it resolves, and whether it is about to be deleted. Misread them and your monitoring misses a suspension, or you wire money for a domain that is five days from dropping.
This is a reference for all of them — the 23 EPP status codes in ICANN's official glossary, which gTLD registries and registrars are required to publish and link, plus the extra values the RDAP protocol adds on top. Every example is from a real lookup we ran while writing this post (July 2026).
One vocabulary, two spellings
The codes come from EPP, the provisioning protocol registrars use to talk to registries (RFC 5731, with the grace-period statuses added by RFC 3915). EPP spells them in camelCase: clientTransferProhibited, pendingDelete, redemptionPeriod.
RDAP — the protocol that replaced WHOIS for reading this data — respells the same vocabulary in lowercase with spaces: client transfer prohibited, pending delete, redemption period (RFC 9083 §10.2.2). RFC 8056 defines the one-to-one mapping between the two forms, and ok becomes active on the way through.
Both spellings mean exactly the same thing. In the wild you will meet both, because some RDAP servers ship the EPP wire form despite the spec. Our API translates everything to the RDAP form, so clientTransferProhibited, Client Transfer Prohibited, and client transfer prohibited all come out as the same string — the full rules are in why we normalize RDAP responses. This post uses the EPP spellings for headings, since that is what people search for, and the RDAP form in JSON examples, since that is what our API returns.
How to read any status array
Three prefix rules decode most of the vocabulary before you memorize a single code:
client*— set by the registrar (GoDaddy, Namecheap, Cloudflare…). The registrar can remove it, and for most codes so can you, through the registrar's control panel.server*— set by the registry (Verisign for.com, PIR for.org…). Your registrar cannot remove it. You escalate, or you deal with the registry's process.- No prefix — a state of the domain itself:
ok/active,inactive, thepending*operations, and the grace periods.
That splits the 23 EPP codes into four families: eight locks, two holds, eleven lifecycle states, and two descriptions of the domain itself.
The locks: *TransferProhibited, *UpdateProhibited, *DeleteProhibited, *RenewProhibited
clientTransferProhibited
Registrars set this one by default, because the alternative is domain hijacking by transfer request — which makes it the status code you will meet more than any other. It blocks transfers to another registrar. Our own domain shows exactly one status:
{ "domain": "rdapapi.io", "status": ["client transfer prohibited"] }
If you see it on a domain you are trying to transfer, it is not an error — you unlock the domain at the current registrar first, which is the intended friction.
clientDeleteProhibited and clientUpdateProhibited
Same idea for deletion and for changes to contacts or nameservers. Registrars bundle the three together as "domain lock" or "registrar lock". That is the first three codes on google.com above.
clientRenewProhibited
Blocks renewal. This is the vocabulary's oddball: there is rarely a business reason for a registrar to stop a client from renewing, and on its own it usually signals a billing dispute. In practice you mostly see it as part of a lock-everything bundle — xkcd.com, for example, carries all four client locks:
{
"domain": "xkcd.com",
"status": [
"client delete prohibited", "client renew prohibited",
"client transfer prohibited", "client update prohibited"
]
}
As protection it is mostly theater: it only blocks explicit renew commands, and at registries with auto-renewal (which includes .com) the domain renews at expiry regardless. That is also why registrars can ship it in a bundle without anyone losing a domain over it.
serverTransferProhibited, serverUpdateProhibited, serverDeleteProhibited, serverRenewProhibited
The same four locks, applied at the registry. They appear in two very different situations.
The first is registry lock, a paid, deliberately manual service (Verisign Registry Lock, and equivalents at other registries) where changes require an out-of-band process with humans and passphrases. This is why google.com carries the server* set alongside the client* set. The client locks are a checkbox in a registrar dashboard — anyone who compromises the registrar account can uncheck them. The server locks are what actually stops a hijack. If a domain is worth a phishing campaign against your registrar, it is worth registry lock. (Sharp-eyed readers will have noticed our own domain a section up shows only the default lock. The advice stands; so does our to-do list.)
The second is legal seizure. Here is z-lib.org, seized by the US Department of Justice, as returned by the .org registry today:
"status": [
"server delete prohibited", "server renew prohibited", "client transfer prohibited",
"server transfer prohibited", "client update prohibited", "server update prohibited"
]
Nobody is moving, editing, or deleting that domain — and note server renew prohibited, the rare fourth lock: the registry has also frozen its renewal state. When you see a wall of server* locks on a domain that is not a famous brand, court order is the usual explanation.
The holds: clientHold and serverHold
The locks above restrict changes but leave the domain working. The holds are different: a domain on hold is removed from the TLD zone file. DNS stops resolving, the website goes dark, and email bounces — while the registration itself continues to exist. For monitoring purposes, hold codes are the difference between "someone locked the doors" and "the power has been cut": the building is still there, but nothing in it works.
clientHold
The registrar suspended the domain. Common causes:
- Failed contact verification. Under ICANN's 2013 Registrar Accreditation Agreement, registrars must verify the registrant's email within 15 days of registration or certain contact changes — and suspend the domain if the registrant never clicks the link. The classic "my website disappeared overnight" support ticket is an unclicked verification email.
- Expiry. Some registrars put expired domains on
clientHoldduring the renewal grace window, taking the site offline until the bill is paid. - Abuse complaints against the domain.
This is the least informative code in the vocabulary: one string covers everything from an unclicked verification email to a serious abuse report — and, at some registrars, a pressure tactic, since suspending an expired domain instead of leaving it resolving makes the renewal notice impossible to ignore. The status code alone does not tell you which story you are in; the expiration date sitting next to it usually does.
serverHold
The registry suspended the domain. Registrar support cannot fix this, whatever their first-line reply says. Causes: DNS abuse programs (phishing and malware takedowns), court orders, ccTLD policy enforcement, and registry disputes with the registrar itself. If your domain shows serverHold and you believe it is a mistake, your path runs through the registry's or registrar's abuse process, with evidence.
serverHold on a domain you are evaluating — as a buyer, or as a security analyst scoring a sender — is the strongest negative signal a status array can carry: some institution with authority over the TLD decided this domain should not resolve.
The deletion pipeline: what expiry actually looks like
Nothing about domain expiry is instant. A .com that expires today can survive, still recoverable, for up to 75 more days — how much of that you actually get depends on when the registrar deletes it. Here is the pipeline, with the real dates of a domain that was mid-drop while we wrote this — schaumburgrent.com, registered in 2006, renewed for twenty years, expired 2026-04-25:
| Stage | Status code | Duration | What it means |
|---|---|---|---|
| Expiry day | (often nothing visible) | — | The registry silently auto-renews and bills the registrar |
| Grace | autoRenewPeriod |
0–45 days | Registrar can still delete for a refund; registrant can renew at the normal price |
| Deleted | redemptionPeriod |
30 days | Original registrant can still restore it — for a fee |
| Restore filed | pendingRestore |
7 days | Registrar has filed a restore and must submit a report |
| Point of no return | pendingDelete |
5 days | Nobody can save it; it will drop |
After twenty years of renewals, the domain expired April 25, its registrar deleted it in early June (inside the 45-day window), it sat in redemption for 30 days, and on July 6 it flipped to ["pending delete"]. We re-ran the lookups a few days after writing that paragraph and caught the ending. It dropped on schedule and was re-registered within hours, through Namecheap, on a fresh one-year term. Its sibling rialtorent.com was re-registered at 18:13 UTC on drop day — by a registrar named "DropCatch.com 768 LLC", which tells you exactly who wins these races. A third from the same batch, mckinneyrent.com, still returns a 404 and is genuinely available.
That ending hides a second lesson: RDAP has no memory. Look up schaumburgrent.com today and you see a 2026 registration date, a 2027 expiry, and no trace of the twenty years that came before. A drop resets the record completely — if the history matters to you, you need snapshots taken while it still existed.
Another expiring domain we checked was caught mid-pipeline showing ["client transfer prohibited", "pending delete"] — a transfer lock on a domain that is being deleted. Registrar-set statuses often persist as residue through lifecycle changes; read the array as a whole, not code by code.
Three codes in this family deserve their own warnings:
autoRenewPeriod hides a trap in the expiration date, not the status. When the registry auto-renews at expiry, the expiration date in RDAP jumps a full year forward — before anyone has paid. While researching this post we found gorod-lugansk.com on a public drop watchlist in July 2026 while its RDAP record showed an expiration of June 2027. An expiration date twelve months out can belong to a domain that expired last month and is still on track to drop. Whether the grace-period statuses are visible at all varies by registry, so their absence proves nothing.
redemptionPeriod (RFC 3915's Registry Grace Period) means the previous registrant can still get the domain back, typically for a $70–200 restore fee on top of renewal. If you are waiting to catch a domain, redemptionPeriod means "not yet, and maybe never". If you just lost a domain you meant to keep, it means "pay the fee today".
pendingDelete is the only truly irreversible status. The domain drops within five days, and the only way to get it is backorder services fighting over the drop. We checked a public drop list against the registry while writing this: eleven of its fifteen .com entries (rialtorent.com, schaumburgrent.com, americusrent.com, …) were already in pending delete; the other four had not been deleted yet and showed nothing but a leftover client transfer prohibited. The registry publishes this status reliably — the lists lag it.
addPeriod, renewPeriod, and transferPeriod are the boring cousins: five-day accounting windows after a new registration, an explicit renewal, or a transfer, during which the registrar can undo the operation for credit. You will occasionally see addPeriod on a days-old domain. None of them require action.
The pending operations: pendingCreate, pendingRenew, pendingTransfer, pendingUpdate
Transient states while an EPP operation waits for registry approval. Most TLDs process creates, renews, and updates synchronously, so pendingCreate, pendingRenew, and pendingUpdate are rare outside registries with manual review or launch phases.
pendingTransfer is the one to watch: the domain is mid-transfer between registrars for up to five days. On your own portfolio, an unexpected pendingTransfer may be a hijack in progress and is worth an immediate page either way — it is also exactly what the transfer locks above exist to prevent.
ok, active, and inactive
ok (EPP) and active (RDAP) are the same status, and it means something narrower than it sounds: no locks, no holds, no pending operations. Here is the counterintuitive part — a valuable domain should not show ok. From our lookups:
{ "domain": "sqlite.org", "status": ["active"] }
{ "domain": "google.com", "status": ["client delete prohibited", "client transfer prohibited", "..."] }
An active-only array means the domain has no transfer lock, and even long-lived, well-run projects turn out to be missing one — the fix is usually a single checkbox at the registrar. For a domain you own, active alone is a to-do item, not a clean bill of health.
inactive means the domain has no delegated nameservers: registered, but pointing nowhere. Normal for parked or defensively registered names; on a domain that had working nameservers yesterday, it is a misconfiguration or something worse.
The RDAP-only statuses
RDAP's status vocabulary is a superset of EPP's. RFC 9083 adds values you will mostly meet on entity and nameserver objects rather than domains: validated, proxy, private, obscured, removed, associated, locked, plus unqualified forms of the four locks (transfer prohibited with no client/server prefix). The IANA registry also lists administrative and reserved, registered by the RIRs — you meet those on IP and ASN records, not domains. ARIN returns exactly ["reserved"] for the RFC 1918 private block 10.0.0.0/8, for example.
On top of the official vocabulary, registries invent their own. AFNIC (.fr) ships server recover prohibited — here is lemonde.fr today, fully registry-locked in AFNIC's dialect:
"status": [
"server update prohibited", "server transfer prohibited",
"server delete prohibited", "server recover prohibited"
]
Other registries emit premium or reserved variants of their own spelling. Per the spec these pass through as opaque strings — our API lowercases them and passes them along rather than guessing at their meaning.
What to alert on
If you monitor domains — your own portfolio, your customers', or domains you want to catch — status codes are only half the signal. The other half is the transition:
| Transition | Severity | Meaning |
|---|---|---|
serverHold appears |
Critical | Registry took the domain offline |
clientHold appears |
Critical | Registrar suspension — verification, expiry, or abuse |
pendingTransfer appears (unexpected) |
Critical | Possible hijack in progress |
| Transfer/update locks disappear | High | Someone is preparing to move the domain |
redemptionPeriod appears |
High | Owner let it lapse; ~30 days to restore |
pendingDelete appears |
High | Drops within 5 days, irreversibly |
inactive appears |
Medium | Nameservers removed |
autoRenewPeriod appears |
Medium | Expired; registrar grace window running |
addPeriod, renewPeriod, transferPeriod appear |
Low | Routine accounting windows — no action needed |
A snapshot tells you where a domain is; a diff against yesterday's snapshot tells you what happened. That is the model behind monitoring domain expiration with code — the same loop covers status codes.
Check a domain's status codes right now
One call, statuses already normalized to the RFC 8056 RDAP form regardless of how the registry spelled them:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://rdapapi.io/api/v1/domain/example.com
{
"domain": "example.com",
"status": ["client delete prohibited", "client transfer prohibited", "client update prohibited"],
"dates": { "expires": "2026-08-13T04:00:00Z" }
}
The same lookup in our SDKs:
# pip install rdapapi
from rdapapi import RdapApi
api = RdapApi("YOUR_TOKEN")
domain = api.domain("example.com")
print(domain.status)
// npm install rdapapi
import { RdapClient } from "rdapapi";
const api = new RdapClient("YOUR_TOKEN");
const { status } = await api.domain("example.com");
// composer require rdapapi/rdapapi-php
$api = new \RdapApi\RdapApi("YOUR_TOKEN");
$status = $api->domain("example.com")->status;
// go get github.com/rdapapi/rdapapi-go
client := rdapapi.NewClient("YOUR_TOKEN")
domain, _ := client.Domain("example.com", nil)
fmt.Println(domain.Status)
// io.rdapapi:rdapapi-java (Maven Central)
RdapClient client = new RdapClient("YOUR_TOKEN");
List<String> status = client.domain("example.com").status();
No API key yet? Try any domain in the browser — every result shows its status codes as badges — or get an API key.
Appendix: the full EPP ↔ RDAP mapping
All 23 EPP domain status codes and their RDAP equivalents per RFC 8056 §2:
| EPP (camelCase) | RDAP (what our API returns) | Set by |
|---|---|---|
ok |
active |
— |
inactive |
inactive |
— |
clientTransferProhibited |
client transfer prohibited |
Registrar |
clientUpdateProhibited |
client update prohibited |
Registrar |
clientDeleteProhibited |
client delete prohibited |
Registrar |
clientRenewProhibited |
client renew prohibited |
Registrar |
clientHold |
client hold |
Registrar |
serverTransferProhibited |
server transfer prohibited |
Registry |
serverUpdateProhibited |
server update prohibited |
Registry |
serverDeleteProhibited |
server delete prohibited |
Registry |
serverRenewProhibited |
server renew prohibited |
Registry |
serverHold |
server hold |
Registry |
pendingCreate |
pending create |
Registry |
pendingRenew |
pending renew |
Registry |
pendingTransfer |
pending transfer |
Registry |
pendingUpdate |
pending update |
Registry |
pendingDelete |
pending delete |
Registry |
pendingRestore |
pending restore |
Registry |
addPeriod |
add period |
Registry |
renewPeriod |
renew period |
Registry |
transferPeriod |
transfer period |
Registry |
autoRenewPeriod |
auto renew period |
Registry |
redemptionPeriod |
redemption period |
Registry |