# EPP Deep Dive

Canonical: https://learndns.org/learn/3-8-epp-deep-dive/

> The Extensible Provisioning Protocol — how registrars communicate with registries to create, manage, transfer, and delete domain names.

Every time you register a domain, renew it, transfer it, or update its nameservers, a protocol called **EPP** carries that action from your registrar to the registry. EPP is the invisible plumbing of the domain registration system — unseen by end users but essential to every operation in the domain ecosystem.

Understanding EPP gives you a view behind the curtain: what actually happens when you click "Register," how status codes control your domain's behavior, and why certain operations take the time they do.

## What is EPP?

The **Extensible Provisioning Protocol** is an XML-based client-server protocol designed for provisioning and managing objects stored in a shared central repository — in practice, domain names, contacts, and hosts (nameservers) in a registry database.

EPP was developed by the IETF and is defined across several RFCs:

| RFC | Title | Purpose |
|-----|-------|---------|
| RFC 5730 | EPP | Core protocol framework |
| RFC 5731 | EPP Domain Name Mapping | Domain-specific commands |
| RFC 5732 | EPP Host Mapping | Nameserver object commands |
| RFC 5733 | EPP Contact Mapping | Contact object commands |
| RFC 5734 | EPP Transport over TCP | Network transport specification |

EPP replaced earlier, registry-specific protocols (like the RRP — Registry Registrar Protocol used by Verisign) with a standardized system that works across all ICANN-accredited registries.

## Architecture

EPP uses a client-server model over persistent TCP connections with TLS encryption:

```
┌──────────────┐         TLS/TCP          ┌──────────────┐
│   Registrar  │◄───────────────────────►│   Registry    │
│  (EPP Client)│    Port 700 (standard)   │  (EPP Server) │
└──────────────┘                          └──────────────┘
```

Key architectural features:

- **Persistent connections**: Unlike HTTP (traditionally), EPP maintains long-lived TCP connections. A registrar opens a session, authenticates, and sends commands over that session.
- **Synchronous request-response**: Each command gets exactly one response. No streaming, no callbacks.
- **Stateful sessions**: After login, the server tracks the client's authentication state.
- **XML-based**: All messages are well-formed XML documents with strict schema validation.

## The Session Lifecycle

An EPP session follows a fixed pattern:

### 1. Greeting

When a client connects, the server immediately sends a `<greeting>` containing:
- Server name and version
- Supported protocol versions
- Supported languages
- Supported object types and extensions
- Data collection policy

```xml
<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <greeting>
    <svID>Example Registry EPP Server</svID>
    <svDate>2024-01-15T00:00:00Z</svDate>
    <svcMenu>
      <version>1.0</version>
      <lang>en</lang>
      <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
      <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
      <objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
    </svcMenu>
  </greeting>
</epp>
```

### 2. Login

The client authenticates with credentials:

```xml
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <login>
      <clID>RegistrarX</clID>
      <pw>secretPassword123</pw>
      <options>
        <version>1.0</version>
        <lang>en</lang>
      </options>
      <svcs>
        <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
        <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
      </svcs>
    </login>
  </command>
</epp>
```

### 3. Commands

After login, the client sends commands and receives responses (the bulk of the session).

### 4. Logout

The client terminates the session gracefully:

```xml
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <logout/>
  </command>
</epp>
```

## EPP Commands

EPP defines a set of standard commands for managing domain objects:

### Query Commands

**`<check>`** — Test whether a domain is available for registration:

```xml
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>example.com</domain:name>
  <domain:name>example.net</domain:name>
</domain:check>
```

Response indicates availability:
```xml
<domain:chkData>
  <domain:cd>
    <domain:name avail="0">example.com</domain:name>
    <domain:reason>In use</domain:reason>
  </domain:cd>
  <domain:cd>
    <domain:name avail="1">example.net</domain:name>
  </domain:cd>
</domain:chkData>
```

**`<info>`** — Retrieve detailed information about a domain:

```xml
<domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name hosts="all">example.com</domain:name>
  <domain:authInfo>
    <domain:pw>authSecret123</domain:pw>
  </domain:authInfo>
</domain:info>
```

The response includes registrant, contacts, nameservers, status codes, dates, and auth info (if the querier is the sponsoring registrar).

### Transform Commands

**`<create>`** — Register a new domain:

```xml
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>newdomain.com</domain:name>
  <domain:period unit="y">2</domain:period>
  <domain:ns>
    <domain:hostObj>ns1.example.com</domain:hostObj>
    <domain:hostObj>ns2.example.com</domain:hostObj>
  </domain:ns>
  <domain:registrant>contact-123</domain:registrant>
  <domain:contact type="admin">contact-456</domain:contact>
  <domain:contact type="tech">contact-789</domain:contact>
  <domain:authInfo>
    <domain:pw>newAuthCode!@#</domain:pw>
  </domain:authInfo>
</domain:create>
```

**`<update>`** — Modify domain properties (nameservers, contacts, status):

```xml
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>example.com</domain:name>
  <domain:add>
    <domain:ns>
      <domain:hostObj>ns3.example.com</domain:hostObj>
    </domain:ns>
    <domain:status s="clientTransferProhibited"/>
  </domain:add>
  <domain:rem>
    <domain:ns>
      <domain:hostObj>ns1.old-provider.com</domain:hostObj>
    </domain:ns>
  </domain:rem>
</domain:update>
```

**`<delete>`** — Remove a domain from the registry:

```xml
<domain:delete xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>example.com</domain:name>
</domain:delete>
```

**`<renew>`** — Extend the domain's registration period:

```xml
<domain:renew xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>example.com</domain:name>
  <domain:curExpDate>2025-04-03</domain:curExpDate>
  <domain:period unit="y">1</domain:period>
</domain:renew>
```

The `curExpDate` is a safety check — it must match the registry's current expiry date, preventing accidental double-renewals.

**`<transfer>`** — Request, approve, reject, or cancel a domain transfer:

```xml
<domain:transfer op="request"
  xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
  <domain:name>example.com</domain:name>
  <domain:authInfo>
    <domain:pw>authFromCurrentOwner</domain:pw>
  </domain:authInfo>
</domain:transfer>
```

The `op` attribute specifies the operation: `request`, `approve`, `reject`, `cancel`, or `query`. For the full transfer workflow from a registrant's perspective, see [Domain Transfers](/learn/3-6-domain-transfers/).

## EPP Status Codes

Status codes are one of EPP's most important features. They control what operations are allowed on a domain and indicate its current lifecycle state. Status codes come in two varieties:

### Client Status Codes

Set by the **registrar** (the "client" in EPP terminology):

| Code | Meaning |
|------|---------|
| `clientDeleteProhibited` | Registrar prevents deletion |
| `clientHold` | Registrar suspends DNS resolution |
| `clientRenewProhibited` | Registrar prevents renewal |
| `clientTransferProhibited` | Registrar prevents transfer (the "registrar lock") |
| `clientUpdateProhibited` | Registrar prevents modifications |

### Server Status Codes

Set by the **registry** (the "server"):

| Code | Meaning |
|------|---------|
| `serverDeleteProhibited` | Registry prevents deletion |
| `serverHold` | Registry suspends DNS resolution |
| `serverRenewProhibited` | Registry prevents renewal |
| `serverTransferProhibited` | Registry prevents transfer |
| `serverUpdateProhibited` | Registry prevents modifications |

### Lifecycle Status Codes

| Code | Meaning |
|------|---------|
| `ok` | Normal, active — no pending operations or prohibitions |
| `addPeriod` | Within the Add Grace Period after registration |
| `autoRenewPeriod` | Within the Auto-Renew Grace Period |
| `renewPeriod` | Within the Renew Grace Period |
| `transferPeriod` | Within the Transfer Grace Period |
| `redemptionPeriod` | Domain deleted, in redemption (recoverable at high cost) |
| `pendingCreate` | Registration is pending |
| `pendingDelete` | Domain queued for deletion (5-day countdown) |
| `pendingRenew` | Renewal is pending |
| `pendingRestore` | Restoration from redemption is pending |
| `pendingTransfer` | Transfer is in progress |
| `pendingUpdate` | Update is pending |
| `inactive` | Domain has no nameservers delegated |

### Reading Status Codes

A typical active domain might show:

```
Domain Status: clientTransferProhibited
Domain Status: clientDeleteProhibited
```

This means the registrar has locked the domain against transfers and deletions — standard security practice. The absence of `ok` is normal when other status codes are present; `ok` only appears when no other statuses are set.

A domain in trouble might show:

```
Domain Status: serverHold
Domain Status: clientTransferProhibited
```

`serverHold` means the registry has suspended DNS resolution — the domain won't resolve. This happens for abuse (phishing, malware), legal orders, or UDRP decisions.

## EPP Extensions

EPP's "extensible" nature allows registries to add custom functionality beyond the base protocol. Common extensions include:

### DNSSEC Extension (RFC 5910)

Allows registrars to manage DNSSEC delegation signer (DS) records:

```xml
<secDNS:create xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
  <secDNS:dsData>
    <secDNS:keyTag>12345</secDNS:keyTag>
    <secDNS:alg>13</secDNS:alg>
    <secDNS:digestType>2</secDNS:digestType>
    <secDNS:digest>49FD46E6C4B45C55D4AC...</secDNS:digest>
  </secDNS:dsData>
</secDNS:create>
```

### Registry Grace Period Extension (RFC 3915)

Provides grace period status information so registrars can manage AGP deletions and redemption restorations.

### Launch Phase Extension (RFC 8334)

Used during new gTLD launches to handle sunrise periods (trademark holders register first), landrush, and claims notifications.

### Fee Extension

Various registries implement fee extensions to communicate dynamic or premium pricing for certain domain names. Before registering `insurance.com`, the registrar can query the fee extension to discover it costs $10,000/year instead of $10.

## EPP in Practice

### Connection Pools

Registrars managing millions of domains don't open a new connection for each operation. They maintain **connection pools** — persistent EPP sessions to each registry, ready to process commands instantly. A large registrar might maintain dozens of concurrent connections to Verisign's `.com` EPP servers.

### Rate Limiting

Registries impose rate limits on EPP commands. Verisign, for example, limits the number of `<check>` commands per connection per second. This prevents abuse (like checking every possible 3-letter `.com` domain in rapid succession) while ensuring fair access for all registrars.

### Testing Environments

Every registry operates an **OT&E (Operational Test and Evaluation)** environment — a sandbox where registrars test their EPP integration before going live. New registrars must successfully complete OT&E testing to become operational.

## Key Takeaways

- **EPP** (RFC 5730-5734) is the XML protocol connecting registrars to registries for all domain operations
- **Six core commands**: `check`, `info`, `create`, `update`, `delete`, `renew`, plus `transfer` with multiple operations
- **Status codes** control what's allowed — `client*` codes are set by registrars, `server*` by registries
- **`clientTransferProhibited`** is the standard "registrar lock" — enable it on every important domain
- **`serverHold`** stops DNS resolution — a registry enforcement action
- **Extensions** add DNSSEC, grace periods, launch phases, and premium pricing capabilities
- **Persistent connections** and **connection pools** make EPP performant at scale

This completes Part 3 — The Domain Ecosystem. You now understand how domain names are structured, how the registration industry operates, and the protocols and processes that make it all work. In [Part 4](/learn/part-4-index/), we'll explore the security layer: DNSSEC, DNS-over-HTTPS, DNS hijacking, and the ongoing battle to keep the namespace trustworthy.