Introduction
Every domain registration record contains at least one EPP status code. They appear in every WHOIS response, they govern what operations are permitted on the domain, and they change at every significant lifecycle event — registration, transfer, renewal, expiry. Most domain owners never look at them. Most developers treat them as noise in the WHOIS output.
That changes the first time a transfer fails because of a code nobody noticed, or the first time a domain stops resolving because a registrar applied a hold. At that point, understanding what each code means — who set it, why, and what action it requires — becomes urgent.
This article is the complete reference: every EPP status code defined, organized by who sets it and what it signals, with a developer section covering how to parse the status and statusAnalysis fields from the WhoisJSON API to build automated alerts. If you are new to WHOIS data, the WHOIS API JSON response field reference is the recommended starting point.
What Are EPP Status Codes?
EPP status codes are standardized indicators that describe the current state of a domain name and the operations permitted on it. They are defined by the IETF in RFC 5731 and are transmitted between registrars and registries using the Extensible Provisioning Protocol (EPP). The same codes surface in WHOIS and RDAP responses, making them the canonical source of truth for a domain's operational state.
Three properties are worth understanding before looking at individual codes:
- Client codes vs server codes. Codes prefixed
clientare set by the registrar (the company you bought the domain from). Codes prefixedserverare set by the registry (the organization that operates the TLD, such as Verisign for .com). Server codes take absolute priority over client codes and can only be removed by the registry itself — your registrar cannot unilaterally lift a server restriction. - Multiple codes. A domain can carry several codes simultaneously. The full set is returned as an array in the WHOIS/RDAP response. The most common real-world combination is
ok,clientTransferProhibited, andserverTransferProhibited. - Authoritative reference. The ICANN EPP status codes page is the canonical listing. This article adds developer context and programmatic examples that are absent from the ICANN reference.
Client Status Codes
Client codes are set and managed by the registrar. They can be added or removed at the registrant's request (subject to registrar policy) and do not require registry involvement to change.
ok
The baseline status. It means the domain has no restrictions of any kind — no locks, no holds, no pending operations. It appears alone; if displayed alongside any other code in a real WHOIS response, that is a data quality issue, not a valid combination.
ok has no transfer lock and no update lock.
It can be transferred to another registrar or have its nameservers changed without any additional verification step. This is a security risk for domains that are not actively being managed.clientTransferProhibited
The most common EPP code. It blocks outgoing transfers to another registrar. Registrars apply it by default at registration to protect against unauthorized transfers. Removing it requires logging into your registrar account (or contacting support) and explicitly unlocking the domain — a step that should only be done immediately before initiating a transfer, then reversed as soon as the transfer completes.
The presence of clientTransferProhibited does not affect DNS resolution, email delivery, or any other operational aspect of the domain. It exclusively governs registrar-to-registrar transfer.
clientUpdateProhibited
Blocks all modifications to the domain record — nameserver changes, contact data updates, DNSSEC configuration. Commonly paired with code clientTransferProhibited | to create a "domain lock" that prevents both hijacking via nameserver modification and unauthorized transfer. Critical production domains — those running core business infrastructure — should carry both codes permanently.
clientDeleteProhibited
Blocks explicit deletion of the domain. Note that it does not prevent natural expiry — if the domain is not renewed before the expiry date, it will still enter the grace period and eventually drop regardless of this code. It protects against accidental or malicious deletion commands sent to the registry.
clientRenewProhibited
Blocks explicit renewal commands. Rare in normal operation — typically indicates a registrar-level dispute, a court order, or a compliance hold. If you see this code on a domain you own and did not request it, contact your registrar immediately.
clientHold
Common causes: unpaid registrar invoice, failed WHOIS verification (ICANN requires registrars to validate contact data), a dispute triggered by the registrar's fraud or abuse team, or a court-ordered suspension. Resolution always requires contacting the registrar directly — no registry intervention is involved.
Server Status Codes
Server codes are set by the registry. They cannot be modified by the registrar or the registrant without explicit registry approval. In practice, this means contacting the registry directly or going through a formal process (legal, compliance, or a paid "registry lock" service).
serverTransferProhibited
The registry-level equivalent of clientTransferProhibited. Applied automatically by ICANN policy for 60 days after a new registration or an incoming transfer — this is the Anti-Abuse Transfer Policy lock, designed to prevent domain hijacking immediately after a registration event. After 60 days it is removed automatically, unless the registrar has enrolled the domain in a paid "registry lock" service (common for high-value domains).
Key distinction: unlike the client version, removing serverTransferProhibited requires the registry's involvement. A registrar cannot lift it unilaterally.
serverUpdateProhibited
Blocks all record modifications at the registry level. Used as part of a full "registry lock" (typically a paid service for premium or critical domains), or applied by the registry following a legal dispute such as a UDRP proceeding or a court injunction. A domain under UDRP typically carries both this code and serverTransferProhibited for the duration of the case.
serverDeleteProhibited
Blocks deletion at the registry level. Part of a full registry lock. Also applied automatically during active UDRP proceedings to prevent the losing party from deleting the domain before a decision is enforced.
serverRenewProhibited
Rare. Blocks renewal at the registry level. Signals an active regulatory or legal proceeding. If observed on a domain you own, escalate to your registrar immediately — it may indicate a compliance hold that could result in domain suspension if not addressed.
serverHold
The registry-level equivalent of clientHold. Removes the domain from the DNS zone file. Applied by the registry for legal reasons (court order, UDRP outcome), abuse (confirmed phishing or malware hosting), or financial (outstanding registry fees). Requires registry intervention to lift — the registrar alone cannot resolve it.
Lifecycle (Pending) Status Codes
Pending codes represent in-progress operations. They are transient — they resolve automatically once the operation completes or its timeout expires. You should not take action based on a pending code alone; wait for it to clear and re-query the domain.
pendingCreate
The domain registration has been submitted and is being processed by the registry. Typically clears within minutes to a few hours. No action required.
pendingTransfer
An outgoing transfer to another registrar is in progress. The losing registrar has up to 5 days to approve or reject; if no action is taken, the transfer completes automatically on day 5. Either party can accelerate the process — the gaining registrar by resubmitting, the losing registrar by explicitly approving.
pendingUpdate
A record modification (nameserver change, contact update) has been submitted and is propagating. Clears within a few hours.
pendingRenew
A renewal has been submitted and is being processed. Clears within a few hours.
pendingDelete
Do not confuse pendingDelete with redemptionPeriod. redemptionPeriod is earlier in the lifecycle and still recoverable (at a cost). By the time a domain reaches pendingDelete, normal restoration is no longer possible.
Registry Grace Period (RGP) Codes
Defined by RFC 5731, RGP codes manage the post-deletion recovery window and the grace periods following standard registration events. For a detailed breakdown of the full expiry lifecycle, see what happens when a domain expires.
redemptionPeriod
The domain is effectively suspended — DNS is removed and the domain does not resolve. After the 30-day redemption window closes, the domain moves to pendingDelete and is queued for public release 5 days later.
pendingRestore
A restore request from redemptionPeriod has been submitted. The registrar has up to 7 days to submit a restore report to the registry. If the report is not submitted within that window, the domain reverts to redemptionPeriod and the restoration fails.
autoRenewPeriod
A 45-day grace period applied after an automatic renewal. If the domain is deleted during this window, the registry refunds the renewal fee to the registrar. Used to handle billing failures and registration errors.
renewPeriod
A 5-day grace period applied after a manual renewal command. Same refund mechanism as autoRenewPeriod, but shorter.
transferPeriod
A 5-day grace period applied after an incoming transfer completes. If the domain is deleted during this window, the registry refunds the transfer fee.
Common Combinations and What They Mean
A WHOIS query rarely returns a single code. The table below covers the combinations you will encounter most often in production data.
| Status combination | What it means | Risk level |
|---|---|---|
ok only | No locks active. Domain is fully transferable and updatable. | MEDIUM |
ok + clientTransferProhibited | Standard configuration for a registered domain. Transfer locked, DNS operations unrestricted. | OK |
ok + clientTransferProhibited + clientUpdateProhibited + clientDeleteProhibited | Full client-side domain lock. Recommended for all critical domains. | SECURE |
serverTransferProhibited (only server code) | Recent registration or transfer (<60 days), or registry lock on a premium domain. | OK |
All four server* codes together | Full registry lock. Maximum protection for ultra-critical domains. | SECURE |
clientHold or serverHold | Domain removed from DNS. Site and email are down. | CRITICAL |
redemptionPeriod | Domain expired and deleted. Recovery possible within 30 days at extra cost. | CRITICAL |
pendingDelete | 5 days before public release. Recovery extremely unlikely. | CRITICAL |
Reading EPP Status Codes Programmatically
The WhoisJSON API returns EPP codes in two complementary fields. The status array contains the raw code strings exactly as returned by the registry. The statusAnalysis object — present only when source is rdap — pre-computes the boolean flags you would otherwise derive yourself, eliminating the need for string matching in application code. See the WHOIS API JSON field reference for the full schema.
{
"name": "example.com",
"registered": true,
"source": "rdap",
"status": [
"clientTransferProhibited",
"clientUpdateProhibited",
"serverTransferProhibited"
],
"statusAnalysis": {
"clientTransferProhibited": true,
"clientUpdateProhibited": true,
"serverTransferProhibited": true,
"clientDeleteProhibited": false,
"serverDeleteProhibited": false,
"isActive": true,
"isOnHold": false,
"isPendingDelete": false,
"isPendingTransfer": false,
"isRedemptionPeriod": false
}
}
Python — alert on critical codes
The following function checks the statusAnalysis object for the three codes that require immediate action and sends an alert for each one found. For the full async query pattern, see the Python WHOIS API guide.
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://whoisjson.com/api/v1"
def check_epp_status(domain: str) -> dict:
resp = requests.get(
f"{BASE}/whois",
params={"domain": domain},
headers={"Authorization": f"TOKEN={API_KEY}"},
timeout=10,
)
resp.raise_for_status()
data = resp.json()
analysis = data.get("statusAnalysis") or {}
alerts = []
if analysis.get("isOnHold"):
alerts.append({
"code": "clientHold or serverHold",
"message": "Domain is on hold — DNS removed, site and email are down.",
"action": "Contact registrar immediately.",
})
if analysis.get("isPendingDelete"):
alerts.append({
"code": "pendingDelete",
"message": "Domain will be released in ~5 days.",
"action": "Contact registrar and registry — options are extremely limited.",
})
if analysis.get("isRedemptionPeriod"):
alerts.append({
"code": "redemptionPeriod",
"message": "Domain expired. Recovery window: 30 days.",
"action": "Submit restore request via registrar before window closes.",
})
return {
"domain": domain,
"status_codes": data.get("status", []),
"is_active": analysis.get("isActive", False),
"transfer_ok": not (
analysis.get("clientTransferProhibited") or
analysis.get("serverTransferProhibited")
),
"alerts": alerts,
}
result = check_epp_status("example.com")
if result["alerts"]:
for alert in result["alerts"]:
print(f"[ALERT] {alert['code']}: {alert['message']}")
print(f" Action: {alert['action']}")
else:
print(f"OK — {result['domain']} is active. Transfer allowed: {result['transfer_ok']}")
Node.js — check if a domain is transferable
The clientTransferProhibited and serverTransferProhibited flags together determine whether an outgoing transfer can be initiated. For more Node.js patterns, see the Node.js WHOIS API guide.
const API_KEY = "YOUR_API_KEY";
const BASE = "https://whoisjson.com/api/v1";
async function isTransferable(domain) {
const resp = await fetch(`${BASE}/whois?domain=${domain}`, {
headers: { Authorization: `TOKEN=${API_KEY}` },
signal: AbortSignal.timeout(10_000),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
const sa = data.statusAnalysis ?? {};
return {
domain,
transferable: !sa.clientTransferProhibited && !sa.serverTransferProhibited,
locked: sa.clientTransferProhibited || sa.clientUpdateProhibited,
onHold: sa.isOnHold ?? false,
pendingDelete: sa.isPendingDelete ?? false,
statusCodes: data.status ?? [],
};
}
const result = await isTransferable("example.com");
console.log(result);
// { domain: 'example.com', transferable: false, locked: true, onHold: false, ... }
EPP Status Codes for Security Monitoring
Beyond operational checks, EPP codes are useful security signals. Three patterns are worth building automated detection for.
- No
clientTransferProhibitedon an owned domain. A domain in your inventory that only carriesokhas no transfer lock. It can be stolen via a social-engineering attack on your registrar's support team without any additional verification. Flag it in your domain inventory sweep and lock it immediately. See domain monitoring for security teams for how to automate this check across a portfolio. - Sudden appearance of
serverHoldorclientHoldon a monitored domain. A hold that was not preceded by a known operational event (expired invoice, WHOIS verification request) is a high-severity signal — it may indicate the registrar has received a legal or abuse notice against your domain. TheisOnHoldboolean instatusAnalysisis the cleanest field to watch. -
pendingDeleteon a domain that resembles your brand. A lookalike domain enteringpendingDeletewill be available for re-registration in 5 days. This is the optimal window for defensive registration — query the availability endpoint on day 5 and register immediately if it drops. This pattern connects directly with the phishing domain detection workflow.
Conclusion
Five codes account for the vast majority of operationally relevant situations:
clientTransferProhibited— should be present on every domain you own. If absent, lock it now.clientHold/serverHold— domain is down. Requires immediate action.redemptionPeriod— domain expired. Recovery possible but costly. 30-day window.pendingDelete— 5 days before public release. Escalate immediately.serverTransferProhibited(without client equivalent) — normal for the first 60 days or on registry-locked domains.
The WhoisJSON API surfaces all of these via the status array and the pre-computed statusAnalysis object, making it straightforward to build automated portfolio monitoring without manual WHOIS parsing.
Read EPP Codes via API
1,000 free WHOIS lookups/month. statusAnalysis included. No credit card.
Get Your Free API Key