domainnameapi 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +47 -0
- data/LICENSE +201 -0
- data/README.md +995 -0
- data/lib/domainnameapi/client.rb +294 -0
- data/lib/domainnameapi/php.rb +322 -0
- data/lib/domainnameapi/rest.rb +1747 -0
- data/lib/domainnameapi/telemetry.rb +472 -0
- data/lib/domainnameapi/transport.rb +89 -0
- data/lib/domainnameapi/version.rb +6 -0
- data/lib/domainnameapi.rb +16 -0
- metadata +56 -0
data/README.md
ADDED
|
@@ -0,0 +1,995 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="README-TR.md" > TR <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/TR.png" alt="TR" height="20" /></a>
|
|
3
|
+
<a href="README.md"> | EN <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/US.png" alt="EN" height="20" /></a>
|
|
4
|
+
<a href="README-DE.md"> | DE <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/DE.png" alt="DE" height="20" /></a>
|
|
5
|
+
<a href="README-SA.md"> | SA <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/SA.png" alt="AR" height="20" /></a>
|
|
6
|
+
<a href="README-NL.md"> | NL <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/NL.png" alt="NL" height="20" /></a>
|
|
7
|
+
<a href="README-AZ.md"> | AZ <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/AZ.png" alt="AZ" height="20" /></a>
|
|
8
|
+
<a href="README-CN.md"> | CN <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/CN.png" alt="CN" height="20" /></a>
|
|
9
|
+
<a href="README-FR.md"> | FR <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/FR.png" alt="FR" height="20" /></a>
|
|
10
|
+
<a href="README-IT.md"> | IT <img style="padding-top: 8px" src="https://raw.githubusercontent.com/yammadev/flag-icons/master/png/IT.png" alt="IT" height="20" /></a>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
# ruby-dna — DomainNameAPI client for Ruby
|
|
14
|
+
|
|
15
|
+
Register, renew and transfer domains, manage contacts, nameservers, child nameservers, DNS zones and URL forwarding through the DomainNameAPI REST API. `ruby-dna` is a faithful port of [php-dna](https://github.com/domainreseller/php-dna): the same methods, the same requests on the wire and the same return values, verified against php-dna's conformance fixtures.
|
|
16
|
+
|
|
17
|
+
## 📦 Download — always use Releases!
|
|
18
|
+
|
|
19
|
+
⬇️ **Get the latest tested version here: https://github.com/domainreseller/ruby-dna/releases/latest**
|
|
20
|
+
|
|
21
|
+
> ⚠️ Do **not** use the green **Code → Download ZIP** button — that downloads the raw development branch. Release packages are versioned, tested and production-ready.
|
|
22
|
+
|
|
23
|
+
## Installation and Integration Guide
|
|
24
|
+
|
|
25
|
+
### Minimum Requirements
|
|
26
|
+
|
|
27
|
+
- Ruby 2.7 or higher (Recommended 3.3+)
|
|
28
|
+
- No runtime dependencies: only the standard library (`net/http`, `json`, `openssl`).
|
|
29
|
+
|
|
30
|
+
### A) Bundler
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# Gemfile
|
|
34
|
+
gem 'domainnameapi', git: 'https://github.com/domainreseller/ruby-dna.git', tag: 'v1.0.0'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bundle install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### B) Gem file from the release
|
|
42
|
+
|
|
43
|
+
Download `domainnameapi-1.0.0.gem` from the [latest release](https://github.com/domainreseller/ruby-dna/releases/latest), then:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
gem install ./domainnameapi-1.0.0.gem
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### C) Manual usage
|
|
50
|
+
|
|
51
|
+
Download the release archive, copy the `lib` folder into your project and look at the examples in the [examples](examples) folder:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
55
|
+
require 'domainnameapi'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 🔑 API Credentials — Reseller ID & API Key
|
|
59
|
+
|
|
60
|
+
The library talks to the DomainNameAPI REST API and needs exactly two credentials, passed to the constructor:
|
|
61
|
+
|
|
62
|
+
| Parameter | Value |
|
|
63
|
+
|---|---|
|
|
64
|
+
| First | Reseller ID — UUID like `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` |
|
|
65
|
+
| Second | API Key |
|
|
66
|
+
|
|
67
|
+
> 💡 Find your **Reseller ID** and **API Key** in your DomainNameAPI panel under **API Settings**.
|
|
68
|
+
> ⚠️ These are **API credentials** — your panel login details will **not** work here.
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
require 'domainnameapi'
|
|
74
|
+
|
|
75
|
+
reseller_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
|
|
76
|
+
api_key = 'your-api-key'
|
|
77
|
+
|
|
78
|
+
# Live environment
|
|
79
|
+
dna = DomainNameApi::Client.new(reseller_id, api_key)
|
|
80
|
+
|
|
81
|
+
# Test (OTE) environment
|
|
82
|
+
dna = DomainNameApi::Client.new(reseller_id, api_key, true)
|
|
83
|
+
|
|
84
|
+
result = dna.get_details('example.com')
|
|
85
|
+
if result['result'] == 'OK'
|
|
86
|
+
puts result['data']['Dates']['Expiration']
|
|
87
|
+
else
|
|
88
|
+
puts "#{result['error']['Code']}: #{result['error']['Message']}"
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Method names are the snake_case form of php-dna's (`getDetails` → `get_details`, `registerWithContactInfo` → `register_with_contact_info`), with the same parameter order and defaults. Results are plain Ruby Hashes and Arrays with **String keys**, exactly the structure php-dna returns (including string flags such as `'LockStatus' => 'true'` and formatted prices such as `'11.9900'`). Credentials are trimmed, and the test-mode flag also accepts strings: `"true"`, `"1"`, `"on"` and `"yes"` mean test mode, anything else means live.
|
|
93
|
+
|
|
94
|
+
## Error handling
|
|
95
|
+
|
|
96
|
+
Methods never raise for API or network problems. A failed call returns an error envelope:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
{
|
|
100
|
+
'result' => 'ERROR',
|
|
101
|
+
'error' => {
|
|
102
|
+
'Code' => 'API_404',
|
|
103
|
+
'Message' => 'The domain name you requested could not be found',
|
|
104
|
+
'Details' => '...'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- `Code` is `API_<HTTP status>` for gateway errors (`API_400`, `API_401`, `API_429`, `API_500`, ...). A `301`/`302` answer means bad credentials (`Invalid API credentials`).
|
|
110
|
+
- When the gateway sends its own error code, the envelope also carries it as `GatewayCode` (e.g. `'GatewayCode' => 'Dna.DomainService:Domain:10007'`), so you can tell one `API_404` from another.
|
|
111
|
+
- An empty error body becomes a readable message such as `HTTP 429 - Too Many Requests`. The raw response body is never used as the message when the gateway's message is boilerplate; a stable text naming the gateway code is used instead.
|
|
112
|
+
- Field validation errors are flattened into `Details`, e.g. `Admin PostalCode - 'PostalCode' is required`.
|
|
113
|
+
- Network failures are errors, never an empty success. A timeout reads `Could not reach the DomainNameAPI service: the connection timed out. (...)`; other transport failures read `Curl error during request: ...`. Their codes are `CURL_<n>` with curl's numbers (`CURL_28` timeout, `CURL_6` DNS, `CURL_7` connection refused, `CURL_35`/`CURL_60` TLS, `CURL_56` reset); `API_<n>` is reserved for HTTP statuses.
|
|
114
|
+
- A registration, transfer or renewal that the gateway answers with HTTP 200 but `"success": false` is a refusal, not a success: it returns the error envelope with code `REGISTER_DOMAIN`, `TRANSFER_DOMAIN` or `RENEW_DOMAIN` and the gateway's message.
|
|
115
|
+
- `get_current_balance` keeps its own envelope: `'OperationResult' => 'FAILED'` with `ErrorCode` and `OperationMessage`.
|
|
116
|
+
- `check_availability` returns a plain list on success and the error envelope on failure.
|
|
117
|
+
|
|
118
|
+
Only programmer errors raise (for example `set_resource_record_set` with `contents` that is not a list raises `TypeError`).
|
|
119
|
+
|
|
120
|
+
Timeouts are 30 seconds per call and 10 seconds to connect. Calls to the DNS zone endpoints are kept at least one second apart, because the gateway answers `HTTP 429` to bursts.
|
|
121
|
+
|
|
122
|
+
### Diagnostics
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
dna.get_request_data # { 'url' => ..., 'method' => 'GET', 'payload' => {...} } of the last call
|
|
126
|
+
dna.get_response_data # last decoded response body (or { 'raw_response' => body })
|
|
127
|
+
dna.get_response_headers # { 'url', 'http_code', 'headers', 'total_time' }
|
|
128
|
+
dna.get_parsed_response_data # last parsed body, or the last error { 'Code', 'Message', 'Details' }
|
|
129
|
+
dna.get_last_function # e.g. 'request:GET domains/info'
|
|
130
|
+
dna.get_service_url # https://api.domainresellerapi.com/api/v1
|
|
131
|
+
dna.set_service_url('https://ote.domainresellerapi.com/api/v1')
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Test mode
|
|
135
|
+
|
|
136
|
+
Pass `true` as the third constructor argument to use the OTE test gateway (`https://ote.domainresellerapi.com/api/v1`). Live calls go to `https://api.domainresellerapi.com/api/v1`. Test mode uses separate test credentials.
|
|
137
|
+
|
|
138
|
+
## Error reporting (telemetry)
|
|
139
|
+
|
|
140
|
+
When an API call fails, the library can send an error report to DomainNameAPI's own error tracker (Sentry). A small random share of successful calls (4%, plus every call slower than 1 second) can be sent as a performance record. This helps DomainNameAPI find and fix problems. Error reporting is **on by default**.
|
|
141
|
+
|
|
142
|
+
> ℹ️ In version 1.0.0 the Sentry project for ruby-dna does not exist yet, so the built-in DSN is empty and **nothing is sent**. Reports start once a release ships the DSN. `DomainNameApi::Client.new(id, key, false, sentry_dsn: '...')` sets one explicitly.
|
|
143
|
+
|
|
144
|
+
**What is sent:**
|
|
145
|
+
|
|
146
|
+
- error code and message
|
|
147
|
+
- called endpoint path and HTTP method
|
|
148
|
+
- call duration
|
|
149
|
+
- library name (`DomainNameAPI-Ruby`), library version and Ruby version
|
|
150
|
+
- reseller ID and domain name
|
|
151
|
+
- the server's public IP address (looked up via `api.ipify.org`, in the background)
|
|
152
|
+
- the operating-system user name the process runs as
|
|
153
|
+
- the API request and response, including the domain's contact details; only credentials are masked — EPP/auth codes, API keys, passwords and tokens are replaced with `***`
|
|
154
|
+
|
|
155
|
+
**What is never sent:** EPP/auth codes, API keys, passwords or tokens in readable form; method arguments in stack traces.
|
|
156
|
+
|
|
157
|
+
Expected, high-volume errors (domain not found, insufficient balance, invalid credentials, ...) are not reported. Reports are posted from a background thread with short timeouts: they never slow down or break your call.
|
|
158
|
+
|
|
159
|
+
**Why and how long:** the data is used only for usage measurement and early diagnosis of problems, and is kept for 30 days on DomainNameAPI's own Sentry server, after which it is deleted automatically.
|
|
160
|
+
|
|
161
|
+
**How to turn it off:**
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
dna = DomainNameApi::Client.new(reseller_id, api_key)
|
|
165
|
+
dna.set_error_reporting_enabled(false)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Minimal mode** sends only the error code and message, endpoint, timing, versions and the reseller ID — no request/response data, domain, server IP or user name:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
dna.set_telemetry_minimal(true)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
> 🔒 **Security:** TLS certificate verification is on. On a host with an outdated CA bundle it can be switched off with `dna.set_ssl_verification(false)` — this is not recommended; updating the CA bundle is the better fix.
|
|
175
|
+
|
|
176
|
+
## Usage
|
|
177
|
+
|
|
178
|
+
All examples assume `dna = DomainNameApi::Client.new(reseller_id, api_key)`. Runnable scripts for every method are in [examples](examples).
|
|
179
|
+
|
|
180
|
+
### Account
|
|
181
|
+
|
|
182
|
+
#### Reseller details
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
dna.get_reseller_details
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
<details>
|
|
189
|
+
<summary>Sample output</summary>
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
{
|
|
193
|
+
'result' => 'OK',
|
|
194
|
+
'id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
|
|
195
|
+
'active' => true,
|
|
196
|
+
'name' => 'example-reseller',
|
|
197
|
+
'balance' => '601.64',
|
|
198
|
+
'currency' => 'USD',
|
|
199
|
+
'symbol' => '$',
|
|
200
|
+
'balances' => [
|
|
201
|
+
{ 'balance' => '601.64', 'currency' => 'USD', 'symbol' => '$' },
|
|
202
|
+
{ 'balance' => '1250.50', 'currency' => 'TL', 'symbol' => 'TL' }
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
</details>
|
|
208
|
+
|
|
209
|
+
#### Current balance
|
|
210
|
+
|
|
211
|
+
`get_current_balance(currency = 'USD')` — the account reports `'USD'` and `'TRY'` balances. For any other currency (`'EUR'`, `'GBP'`, ...) the call fails with `'ErrorCode' => 'BALANCE'` instead of answering `0.00`.
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
dna.get_current_balance('USD')
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
<details>
|
|
218
|
+
<summary>Sample output</summary>
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
{
|
|
222
|
+
'ErrorCode' => 0,
|
|
223
|
+
'OperationMessage' => 'Command completed succesfully.',
|
|
224
|
+
'OperationResult' => 'SUCCESS',
|
|
225
|
+
'Balance' => '601.64',
|
|
226
|
+
'CurrencyId' => 2,
|
|
227
|
+
'CurrencyInfo' => nil,
|
|
228
|
+
'CurrencyName' => 'USD',
|
|
229
|
+
'CurrencySymbol' => '$'
|
|
230
|
+
}
|
|
231
|
+
# get_current_balance('EUR')
|
|
232
|
+
{
|
|
233
|
+
'ErrorCode' => 'BALANCE',
|
|
234
|
+
'OperationMessage' => 'No EUR balance is reported for this account. Available: USD, TRY.',
|
|
235
|
+
'OperationResult' => 'FAILED',
|
|
236
|
+
'Balance' => '0.00',
|
|
237
|
+
'CurrencyId' => 3,
|
|
238
|
+
'CurrencyInfo' => nil,
|
|
239
|
+
'CurrencyName' => 'EUR',
|
|
240
|
+
'CurrencySymbol' => '€'
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
</details>
|
|
245
|
+
|
|
246
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
247
|
+
|
|
248
|
+
### Search and lists
|
|
249
|
+
|
|
250
|
+
#### Domain availability check
|
|
251
|
+
|
|
252
|
+
`check_availability(domains, extensions, period, command = 'create')` — `DomainName` in the result is the name without its trailing `.tld`.
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
dna.check_availability(['hello', 'world123x0'], ['com', 'net'], 1, 'create')
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
<summary>Sample output</summary>
|
|
260
|
+
|
|
261
|
+
```ruby
|
|
262
|
+
[
|
|
263
|
+
{ 'TLD' => 'com', 'DomainName' => 'hello', 'Status' => 'notavailable', 'Command' => 'create',
|
|
264
|
+
'Period' => 1, 'IsFee' => false, 'Price' => '10.8100', 'Currency' => 'USD', 'Reason' => 'Domain exists' },
|
|
265
|
+
{ 'TLD' => 'com', 'DomainName' => 'world123x0', 'Status' => 'available', 'Command' => 'create',
|
|
266
|
+
'Period' => 1, 'IsFee' => false, 'Price' => '10.8100', 'Currency' => 'USD', 'Reason' => nil }
|
|
267
|
+
]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
</details>
|
|
271
|
+
|
|
272
|
+
#### Domain list
|
|
273
|
+
|
|
274
|
+
`get_list(extra_parameters = {})` — `PageNumber` (0-based), `PageSize`, `OrderColumn`, `OrderDirection` and the gateway's own filters (e.g. `DomainName`).
|
|
275
|
+
|
|
276
|
+
```ruby
|
|
277
|
+
dna.get_list('OrderColumn' => 'Id', 'OrderDirection' => 'ASC', 'PageNumber' => 0, 'PageSize' => 1000)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
<details>
|
|
281
|
+
<summary>Sample output</summary>
|
|
282
|
+
|
|
283
|
+
```ruby
|
|
284
|
+
{
|
|
285
|
+
'data' => {
|
|
286
|
+
'Domains' => [
|
|
287
|
+
{
|
|
288
|
+
'ID' => 564346, 'Status' => 'Active', 'DomainName' => 'example.com', 'AuthCode' => '',
|
|
289
|
+
'LockStatus' => 'true', 'PrivacyProtectionStatus' => 'false', 'IsChildNameServer' => 'false',
|
|
290
|
+
'Contacts' => { 'Billing' => { 'ID' => '' }, 'Technical' => { 'ID' => '' },
|
|
291
|
+
'Administrative' => { 'ID' => '' }, 'Registrant' => { 'ID' => '' } },
|
|
292
|
+
'Dates' => { 'Start' => '2024-03-15T10:00:00', 'Expiration' => '2027-03-15T10:00:00', 'RemainingDays' => 126 },
|
|
293
|
+
'NameServers' => ['ns1.example.com', 'ns2.example.com'],
|
|
294
|
+
'Additional' => {},
|
|
295
|
+
'ChildNameServers' => []
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
'result' => 'OK',
|
|
300
|
+
'TotalCount' => 1
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
</details>
|
|
305
|
+
|
|
306
|
+
#### TLD list
|
|
307
|
+
|
|
308
|
+
`get_tld_list(count = 20)`
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
dna.get_tld_list(100)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
<details>
|
|
315
|
+
<summary>Sample output</summary>
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
{
|
|
319
|
+
'data' => [
|
|
320
|
+
{
|
|
321
|
+
'id' => 1, 'status' => 'Active', 'maxchar' => 63, 'maxperiod' => 10, 'minchar' => 1, 'minperiod' => 1,
|
|
322
|
+
'tld' => 'com',
|
|
323
|
+
'pricing' => {
|
|
324
|
+
'registration' => { '1' => '10.8100' },
|
|
325
|
+
'renew' => { '1' => '11.0100' },
|
|
326
|
+
'transfer' => { '1' => '10.6100' },
|
|
327
|
+
'restore' => { '1' => '99.9000' }
|
|
328
|
+
},
|
|
329
|
+
'currencies' => { 'registration' => 'USD', 'renew' => 'USD', 'transfer' => 'USD', 'restore' => 'USD' }
|
|
330
|
+
}
|
|
331
|
+
],
|
|
332
|
+
'result' => 'OK'
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
</details>
|
|
337
|
+
|
|
338
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
339
|
+
|
|
340
|
+
### Domain
|
|
341
|
+
|
|
342
|
+
#### Domain registration
|
|
343
|
+
|
|
344
|
+
`register_with_contact_info(domain, period, contacts, name_servers = [], epp_lock = true, privacy_lock = false, additional_attributes = {})`
|
|
345
|
+
|
|
346
|
+
Contacts use php-dna's keys. Both the flat shape below and the nested one returned by `get_contacts` (`Address => { Line1, City, ... }`, `Phone => { Phone => { Number, CountryCode } }`) are accepted; missing fields are completed and names, phones and countries are normalized (see `validate_contact`). With no nameservers, `ns1.domainnameapi.com` and `ns2.domainnameapi.com` are used.
|
|
347
|
+
|
|
348
|
+
```ruby
|
|
349
|
+
contact = {
|
|
350
|
+
'FirstName' => 'John',
|
|
351
|
+
'LastName' => 'Doe',
|
|
352
|
+
'Company' => 'Example Corp',
|
|
353
|
+
'EMail' => 'john.doe@example.com',
|
|
354
|
+
'AddressLine1' => '123 Lorem Street',
|
|
355
|
+
'AddressLine2' => 'Suite 456',
|
|
356
|
+
'AddressLine3' => '',
|
|
357
|
+
'City' => 'Springfield',
|
|
358
|
+
'Country' => 'US',
|
|
359
|
+
'Fax' => '1234567890',
|
|
360
|
+
'FaxCountryCode' => '1',
|
|
361
|
+
'Phone' => '9876543210',
|
|
362
|
+
'PhoneCountryCode' => 1,
|
|
363
|
+
'Type' => 'Contact',
|
|
364
|
+
'ZipCode' => '12345',
|
|
365
|
+
'State' => 'IL'
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
dna.register_with_contact_info(
|
|
369
|
+
'example.com',
|
|
370
|
+
1,
|
|
371
|
+
{ 'Administrative' => contact, 'Billing' => contact, 'Technical' => contact, 'Registrant' => contact },
|
|
372
|
+
['ns1.example.com', 'ns2.example.com'],
|
|
373
|
+
true,
|
|
374
|
+
false
|
|
375
|
+
)
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
For `.tr` domains pass the TRABIS attributes as the 7th argument:
|
|
379
|
+
|
|
380
|
+
```ruby
|
|
381
|
+
# Individual owner
|
|
382
|
+
{ 'TRABISDOMAINCATEGORY' => 1, 'TRABISCITIZIENID' => '12345678901' }
|
|
383
|
+
# Company owner
|
|
384
|
+
{ 'TRABISDOMAINCATEGORY' => 0, 'TRABISTAXOFFICE' => 'Istanbul VD', 'TRABISTAXNUMBER' => '1234567890' }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
The category is sent as `Owner`/`Corporate`, `TRABISCITIZIENID` as `TRABISCITIZENID`, and legacy keys (`TRABISNAMESURNAME`, `TRABISCOUNTRYID`, `TRABISCITYID`, ...) are dropped, because the gateway now reads them from the contact.
|
|
388
|
+
|
|
389
|
+
<details>
|
|
390
|
+
<summary>Sample output</summary>
|
|
391
|
+
|
|
392
|
+
```ruby
|
|
393
|
+
{
|
|
394
|
+
'data' => {
|
|
395
|
+
'ID' => 123456, 'Status' => 'Active', 'DomainName' => 'example.com', 'AuthCode' => 'Xy9#mK2$pL5@vN8',
|
|
396
|
+
'LockStatus' => 'true', 'PrivacyProtectionStatus' => 'false', 'IsChildNameServer' => 'false',
|
|
397
|
+
'Contacts' => { 'Billing' => { 'ID' => 987654 }, 'Technical' => { 'ID' => 987654 },
|
|
398
|
+
'Administrative' => { 'ID' => 987654 }, 'Registrant' => { 'ID' => 987654 } },
|
|
399
|
+
'Dates' => { 'Start' => '2024-03-15T10:00:00', 'Expiration' => '2025-03-15T10:00:00', 'RemainingDays' => 365 },
|
|
400
|
+
'NameServers' => ['ns1.example.com', 'ns2.example.com'],
|
|
401
|
+
'Additional' => {},
|
|
402
|
+
'ChildNameServers' => []
|
|
403
|
+
},
|
|
404
|
+
'result' => 'OK'
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
</details>
|
|
409
|
+
|
|
410
|
+
#### Domain renewal
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
dna.renew('example.com', 1)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
<details>
|
|
417
|
+
<summary>Sample output</summary>
|
|
418
|
+
|
|
419
|
+
```ruby
|
|
420
|
+
{ 'result' => 'OK', 'data' => { 'ExpirationDate' => '2025-03-15T10:00:00' } }
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
</details>
|
|
424
|
+
|
|
425
|
+
#### Domain details
|
|
426
|
+
|
|
427
|
+
```ruby
|
|
428
|
+
dna.get_details('example.com')
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
<details>
|
|
432
|
+
<summary>Sample output</summary>
|
|
433
|
+
|
|
434
|
+
```ruby
|
|
435
|
+
{
|
|
436
|
+
'data' => {
|
|
437
|
+
'ID' => 564346, 'Status' => 'Active', 'DomainName' => 'example.com', 'AuthCode' => 'DHQ!K52',
|
|
438
|
+
'LockStatus' => 'true', 'PrivacyProtectionStatus' => 'false', 'IsChildNameServer' => 'true',
|
|
439
|
+
'Contacts' => { 'Billing' => { 'ID' => 'DNA-B-4' }, 'Technical' => { 'ID' => 'DNA-T-3' },
|
|
440
|
+
'Administrative' => { 'ID' => 'DNA-A-2' }, 'Registrant' => { 'ID' => 'DNA-R-1' } },
|
|
441
|
+
'Dates' => { 'Start' => '2025-05-26T16:08:37', 'Expiration' => '2027-05-26T16:08:37', 'RemainingDays' => 449 },
|
|
442
|
+
'NameServers' => ['ns1.example.com', 'ns2.example.com'],
|
|
443
|
+
'Additional' => {},
|
|
444
|
+
'ChildNameServers' => [{ 'ns' => 'ns1.example.com', 'ip' => '1.2.3.4' }]
|
|
445
|
+
},
|
|
446
|
+
'result' => 'OK'
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
</details>
|
|
451
|
+
|
|
452
|
+
#### Sync from registry
|
|
453
|
+
|
|
454
|
+
Same call and output as `get_details`.
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
dna.sync_from_registry('example.com')
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### Nameserver modification
|
|
461
|
+
|
|
462
|
+
Pass a list or a Hash (the values are used). Names are trimmed, lower-cased, stripped of a trailing dot and de-duplicated; the result reports that normalised list.
|
|
463
|
+
|
|
464
|
+
```ruby
|
|
465
|
+
dna.modify_name_server('example.com', ['ns1.example.com', 'ns2.example.com'])
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
<details>
|
|
469
|
+
<summary>Sample output</summary>
|
|
470
|
+
|
|
471
|
+
```ruby
|
|
472
|
+
{ 'result' => 'OK', 'data' => { 'NameServers' => ['ns1.example.com', 'ns2.example.com'] } }
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
</details>
|
|
476
|
+
|
|
477
|
+
#### Enable domain lock
|
|
478
|
+
|
|
479
|
+
```ruby
|
|
480
|
+
dna.enable_theft_protection_lock('example.com')
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
<details>
|
|
484
|
+
<summary>Sample output</summary>
|
|
485
|
+
|
|
486
|
+
```ruby
|
|
487
|
+
{ 'result' => 'OK', 'data' => { 'LockStatus' => true } }
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
</details>
|
|
491
|
+
|
|
492
|
+
#### Disable domain lock
|
|
493
|
+
|
|
494
|
+
```ruby
|
|
495
|
+
dna.disable_theft_protection_lock('example.com')
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
<details>
|
|
499
|
+
<summary>Sample output</summary>
|
|
500
|
+
|
|
501
|
+
```ruby
|
|
502
|
+
{ 'result' => 'OK', 'data' => { 'LockStatus' => false } }
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
</details>
|
|
506
|
+
|
|
507
|
+
#### Modify domain privacy
|
|
508
|
+
|
|
509
|
+
`modify_privacy_protection_status(domain, status, reason = 'Owner request')` — `status` may be `true`/`false` or a panel-style value: `1`, `'1'`, `'true'`, `'on'` and `'yes'` enable privacy, anything else disables it. The result reports the parsed boolean. `reason` is accepted for compatibility but not sent: the gateway has no such field.
|
|
510
|
+
|
|
511
|
+
```ruby
|
|
512
|
+
dna.modify_privacy_protection_status('example.com', true, 'Owner request')
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
<details>
|
|
516
|
+
<summary>Sample output</summary>
|
|
517
|
+
|
|
518
|
+
```ruby
|
|
519
|
+
{ 'data' => { 'PrivacyProtectionStatus' => true }, 'result' => 'OK' }
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
</details>
|
|
523
|
+
|
|
524
|
+
#### Get domain contacts
|
|
525
|
+
|
|
526
|
+
Contact types are matched case-insensitively (`admin`/`administrative`, `tech`/`technical`, `registrant`/`owner`, `billing`); other types the registry returns are kept after the four standard ones.
|
|
527
|
+
|
|
528
|
+
```ruby
|
|
529
|
+
dna.get_contacts('example.com')
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
<details>
|
|
533
|
+
<summary>Sample output</summary>
|
|
534
|
+
|
|
535
|
+
```ruby
|
|
536
|
+
{
|
|
537
|
+
'data' => {
|
|
538
|
+
'contacts' => {
|
|
539
|
+
'Administrative' => {
|
|
540
|
+
'ID' => 'DNA-A-2', 'Status' => 'Active', 'AuthCode' => '',
|
|
541
|
+
'FirstName' => 'Grace', 'LastName' => 'Hopper', 'Company' => '', 'EMail' => 'grace@example.com',
|
|
542
|
+
'Type' => 'Administrative',
|
|
543
|
+
'Address' => { 'Line1' => 'Example Street 2', 'Line2' => '', 'Line3' => '', 'State' => 'DC',
|
|
544
|
+
'City' => 'Washington', 'Country' => 'US', 'ZipCode' => '20001' },
|
|
545
|
+
'Phone' => { 'Phone' => { 'Number' => '2025550100', 'CountryCode' => '1' },
|
|
546
|
+
'Fax' => { 'Number' => '2025550101', 'CountryCode' => '1' } },
|
|
547
|
+
'Additional' => {}
|
|
548
|
+
},
|
|
549
|
+
'Billing' => { ... }, 'Registrant' => { ... }, 'Technical' => { ... }
|
|
550
|
+
# any other contact type the registry returns follows these four
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
'result' => 'OK'
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
</details>
|
|
558
|
+
|
|
559
|
+
#### Save domain contacts
|
|
560
|
+
|
|
561
|
+
```ruby
|
|
562
|
+
dna.save_contacts('example.com', {
|
|
563
|
+
'Administrative' => contact,
|
|
564
|
+
'Billing' => contact,
|
|
565
|
+
'Technical' => contact,
|
|
566
|
+
'Registrant' => contact
|
|
567
|
+
})
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
<details>
|
|
571
|
+
<summary>Sample output</summary>
|
|
572
|
+
|
|
573
|
+
```ruby
|
|
574
|
+
{ 'result' => 'OK', 'data' => { 'contacts' => {} } }
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
</details>
|
|
578
|
+
|
|
579
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
580
|
+
|
|
581
|
+
### Child nameservers
|
|
582
|
+
|
|
583
|
+
#### Add child nameserver
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
dna.add_child_name_server('example.com', 'ns1.example.com', '1.2.3.4')
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
<details>
|
|
590
|
+
<summary>Sample output</summary>
|
|
591
|
+
|
|
592
|
+
```ruby
|
|
593
|
+
{ 'result' => 'OK', 'data' => { 'NameServer' => 'ns1.example.com', 'IPAdresses' => ['1.2.3.4'] } }
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</details>
|
|
597
|
+
|
|
598
|
+
#### Delete child nameserver
|
|
599
|
+
|
|
600
|
+
```ruby
|
|
601
|
+
dna.delete_child_name_server('example.com', 'ns1.example.com')
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
<details>
|
|
605
|
+
<summary>Sample output</summary>
|
|
606
|
+
|
|
607
|
+
```ruby
|
|
608
|
+
{ 'result' => 'OK', 'data' => { 'NameServer' => 'ns1.example.com' } }
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
</details>
|
|
612
|
+
|
|
613
|
+
#### Update child nameserver
|
|
614
|
+
|
|
615
|
+
```ruby
|
|
616
|
+
dna.modify_child_name_server('example.com', 'ns1.example.com', '1.2.3.5')
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
<details>
|
|
620
|
+
<summary>Sample output</summary>
|
|
621
|
+
|
|
622
|
+
```ruby
|
|
623
|
+
{ 'result' => 'OK', 'data' => { 'NameServer' => 'ns1.example.com', 'IPAdresses' => ['1.2.3.5'] } }
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
</details>
|
|
627
|
+
|
|
628
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
629
|
+
|
|
630
|
+
### Transfers
|
|
631
|
+
|
|
632
|
+
#### Domain transfer
|
|
633
|
+
|
|
634
|
+
`transfer(domain, epp_code, period)` — a transfer never sends contacts: the registrar handles them, so the request always carries an empty contact list and the method takes no contacts argument. Update contacts with `save_contacts` once the transfer has completed.
|
|
635
|
+
|
|
636
|
+
```ruby
|
|
637
|
+
dna.transfer('example.com', 'Xy9#mK2$', 3)
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
<details>
|
|
641
|
+
<summary>Sample output</summary>
|
|
642
|
+
|
|
643
|
+
```ruby
|
|
644
|
+
{
|
|
645
|
+
'data' => { 'ID' => 0, 'Status' => 'WaitingForIncomingTransfer', 'DomainName' => 'example.com', ... },
|
|
646
|
+
'result' => 'OK'
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
</details>
|
|
651
|
+
|
|
652
|
+
#### Check transfer
|
|
653
|
+
|
|
654
|
+
`result` is `'OK'` only when the registry reports the domain as transferable.
|
|
655
|
+
|
|
656
|
+
```ruby
|
|
657
|
+
dna.check_transfer('example.com', 'Xy9#mK2$')
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
<details>
|
|
661
|
+
<summary>Sample output</summary>
|
|
662
|
+
|
|
663
|
+
```ruby
|
|
664
|
+
{
|
|
665
|
+
'result' => 'OK',
|
|
666
|
+
'data' => {
|
|
667
|
+
'TransferAvailabilityStatus' => true, 'AuthCodeIsRequired' => true, 'AuthCodeIsValid' => true,
|
|
668
|
+
'UserTransferRequired' => false, 'TransferLock' => false, 'Message' => '', 'MessageKey' => '',
|
|
669
|
+
'Additional' => {}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
</details>
|
|
675
|
+
|
|
676
|
+
#### Cancel, approve or reject a transfer
|
|
677
|
+
|
|
678
|
+
`cancel_transfer` cancels a pending incoming transfer; `approve_transfer` and `reject_transfer` answer a pending outgoing one.
|
|
679
|
+
|
|
680
|
+
```ruby
|
|
681
|
+
dna.cancel_transfer('example.com')
|
|
682
|
+
dna.approve_transfer('example.com')
|
|
683
|
+
dna.reject_transfer('example.com')
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
<details>
|
|
687
|
+
<summary>Sample output</summary>
|
|
688
|
+
|
|
689
|
+
```ruby
|
|
690
|
+
{ 'result' => 'OK', 'data' => { 'DomainName' => 'example.com', 'Status' => 'Cancelled' } } # 'Approved' / 'Rejected'
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
</details>
|
|
694
|
+
|
|
695
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
696
|
+
|
|
697
|
+
### DNS zone
|
|
698
|
+
|
|
699
|
+
Supported record types: `A`, `AAAA`, `ALIAS`, `CAA`, `CNAME`, `DS`, `MX`, `NAPTR`, `PTR`, `SRV`, `TLSA`, `TXT` (other types are rejected before any call). Names are relative (`'www'`); `''` or `'@'` is the zone apex, and a full name such as `'www.example.com'` is reduced to its label. Changes are applied immediately; pass `apply = false` to stage several and call `apply_resource_records` once. TTL is 1–86400 seconds.
|
|
700
|
+
|
|
701
|
+
If the automatic apply fails, the method returns the apply error (the change stays staged, not live) instead of `OK`. The result reports the upper-cased type and the TTL that were actually sent.
|
|
702
|
+
|
|
703
|
+
The gateway stores a name + type as one **set**: writing a set replaces all of its values, and deleting one value deletes the whole set. The `*_resource_record_value` methods do the read-merge-write for you.
|
|
704
|
+
|
|
705
|
+
#### List records
|
|
706
|
+
|
|
707
|
+
```ruby
|
|
708
|
+
dna.get_resource_records('example.com')
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
<details>
|
|
712
|
+
<summary>Sample output</summary>
|
|
713
|
+
|
|
714
|
+
```ruby
|
|
715
|
+
{
|
|
716
|
+
'result' => 'OK',
|
|
717
|
+
'data' => {
|
|
718
|
+
'records' => [
|
|
719
|
+
{ 'Name' => 'example.com.', 'Type' => 'MX', 'TTL' => 3600, 'Content' => '10 mail.example.com.', 'Disabled' => false },
|
|
720
|
+
{ 'Name' => 'www.example.com.', 'Type' => 'A', 'TTL' => 3600, 'Content' => '192.0.2.10', 'Disabled' => false }
|
|
721
|
+
]
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
</details>
|
|
727
|
+
|
|
728
|
+
#### Replace a record set
|
|
729
|
+
|
|
730
|
+
`set_resource_record_set(domain, name, type, contents, ttl = 3600, apply = true)` — an empty list removes the set.
|
|
731
|
+
|
|
732
|
+
```ruby
|
|
733
|
+
dna.set_resource_record_set('example.com', 'www', 'A', ['192.0.2.10', '192.0.2.11'], 3600)
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
<details>
|
|
737
|
+
<summary>Sample output</summary>
|
|
738
|
+
|
|
739
|
+
```ruby
|
|
740
|
+
{ 'result' => 'OK', 'data' => { 'Name' => 'www', 'Type' => 'A', 'TTL' => 3600, 'Contents' => ['192.0.2.10', '192.0.2.11'] } }
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
</details>
|
|
744
|
+
|
|
745
|
+
#### Add, replace or remove one value
|
|
746
|
+
|
|
747
|
+
`add_resource_record_value(domain, name, type, value, ttl = nil, apply = true)`, `replace_resource_record_value(domain, name, type, old_value, new_value, ttl = nil, apply = true)`, `remove_resource_record_value(domain, name, type, value, apply = true)`. A `nil` TTL keeps the set's current TTL; adding a value that exists or removing one that does not is a no-op (`'Changed' => false`).
|
|
748
|
+
|
|
749
|
+
```ruby
|
|
750
|
+
dna.add_resource_record_value('example.com', '', 'MX', '10 mail.example.com.')
|
|
751
|
+
dna.replace_resource_record_value('example.com', '', 'MX', '10 mail.example.com.', '20 mail.example.com.')
|
|
752
|
+
dna.remove_resource_record_value('example.com', '', 'MX', '20 mail.example.com.')
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
<details>
|
|
756
|
+
<summary>Sample output</summary>
|
|
757
|
+
|
|
758
|
+
```ruby
|
|
759
|
+
{ 'result' => 'OK', 'data' => { 'Name' => '', 'Type' => 'MX', 'TTL' => 3600, 'Contents' => ['10 mail.example.com.'] } }
|
|
760
|
+
# value already present:
|
|
761
|
+
{ 'result' => 'OK', 'data' => { 'Name' => '', 'Type' => 'MX', 'Contents' => ['10 mail.example.com.'], 'Changed' => false } }
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
</details>
|
|
765
|
+
|
|
766
|
+
#### Delete a record set
|
|
767
|
+
|
|
768
|
+
`delete_resource_record_set(domain, name, type, apply = true, known_value = '')` — removes every value of the set; nothing to remove is a success with `'Removed' => false`.
|
|
769
|
+
|
|
770
|
+
```ruby
|
|
771
|
+
dna.delete_resource_record_set('example.com', 'www', 'A')
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
<details>
|
|
775
|
+
<summary>Sample output</summary>
|
|
776
|
+
|
|
777
|
+
```ruby
|
|
778
|
+
{ 'result' => 'OK', 'data' => { 'Name' => 'www.example.com.', 'Type' => 'A', 'Content' => '192.0.2.10' } }
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
</details>
|
|
782
|
+
|
|
783
|
+
#### Low-level record calls
|
|
784
|
+
|
|
785
|
+
```ruby
|
|
786
|
+
dna.add_resource_record('example.com', 'www', 'A', '192.0.2.10', 3600, true)
|
|
787
|
+
dna.edit_resource_record('example.com', 'www', 'www', 'A', '192.0.2.20', 3600, true)
|
|
788
|
+
dna.delete_resource_record('example.com', 'www.example.com.', '192.0.2.20', 'A', true)
|
|
789
|
+
dna.apply_resource_records('example.com')
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
<details>
|
|
793
|
+
<summary>Sample output</summary>
|
|
794
|
+
|
|
795
|
+
```ruby
|
|
796
|
+
{ 'result' => 'OK', 'data' => { 'Name' => 'www', 'Type' => 'A', 'TTL' => 3600, 'Content' => '192.0.2.10' } } # add / edit
|
|
797
|
+
{ 'result' => 'OK', 'data' => { 'Name' => 'www.example.com.', 'Type' => 'A', 'Content' => '192.0.2.20' } } # delete
|
|
798
|
+
{ 'result' => 'OK', 'data' => { 'DomainName' => 'example.com' } } # apply
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
</details>
|
|
802
|
+
|
|
803
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
804
|
+
|
|
805
|
+
### URL forwarding
|
|
806
|
+
|
|
807
|
+
Forward types: `'Standard'` (plain redirect) and `'Frame'` (masked). The gateway answers `Redirect information not found` when nothing is configured: `get_forwarding` then reports `'Enabled' => false` and `delete_forwarding` succeeds with `'Removed' => false`. Any other error, such as an unknown domain, is returned as an error.
|
|
808
|
+
|
|
809
|
+
```ruby
|
|
810
|
+
dna.set_forwarding('example.com', 'https://www.example.org', 'Standard')
|
|
811
|
+
dna.get_forwarding('example.com')
|
|
812
|
+
dna.delete_forwarding('example.com')
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
<details>
|
|
816
|
+
<summary>Sample output</summary>
|
|
817
|
+
|
|
818
|
+
```ruby
|
|
819
|
+
# set_forwarding
|
|
820
|
+
{ 'result' => 'OK', 'data' => { 'RedirectAddress' => 'https://www.example.org', 'ForwardType' => 'Standard' } }
|
|
821
|
+
# get_forwarding (nothing configured gives Enabled => false, not an error)
|
|
822
|
+
{ 'result' => 'OK', 'data' => { 'Enabled' => true, 'RedirectAddress' => 'https://www.example.org', 'ForwardType' => 'Standard' } }
|
|
823
|
+
# delete_forwarding (Removed => false when nothing was configured)
|
|
824
|
+
{ 'result' => 'OK', 'data' => { 'DomainName' => 'example.com', 'Removed' => true } }
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
</details>
|
|
828
|
+
|
|
829
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
830
|
+
|
|
831
|
+
### Utilities (no network)
|
|
832
|
+
|
|
833
|
+
#### Is it a .tr domain?
|
|
834
|
+
|
|
835
|
+
```ruby
|
|
836
|
+
dna.is_tr_tld('example.com.tr') # => true
|
|
837
|
+
dna.is_tr_tld('example.com') # => false
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
#### Validate a contact
|
|
841
|
+
|
|
842
|
+
Completes and normalizes a contact the way registration does: digits and punctuation are removed from names, a missing state becomes the city, country names become ISO codes and phone numbers are split into number and country code. A number written with its own `+` or `00` calling code keeps that code even when another `PhoneCountryCode` was given (`'+1 202 555 0100'` → `'2025550100'` / `'1'`).
|
|
843
|
+
|
|
844
|
+
```ruby
|
|
845
|
+
dna.validate_contact('FirstName' => 'J0hn', 'Phone' => '+90 532 374 33 88', 'Country' => 'Turkey')
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
<details>
|
|
849
|
+
<summary>Sample output</summary>
|
|
850
|
+
|
|
851
|
+
```ruby
|
|
852
|
+
{
|
|
853
|
+
'FirstName' => 'Jhn', 'Phone' => '5323743388', 'Country' => 'TR', 'LastName' => 'Isimyok',
|
|
854
|
+
'AddressLine1' => 'Addres yok', 'City' => 'ISTANBUL', 'State' => 'ISTANBUL', 'ZipCode' => '34000',
|
|
855
|
+
'PhoneCountryCode' => '90', 'Fax' => '', 'FaxCountryCode' => ''
|
|
856
|
+
}
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
</details>
|
|
860
|
+
|
|
861
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
862
|
+
|
|
863
|
+
### Settings
|
|
864
|
+
|
|
865
|
+
| Method | Effect |
|
|
866
|
+
|---|---|
|
|
867
|
+
| `set_error_reporting_enabled(false)` | Turn telemetry off |
|
|
868
|
+
| `set_telemetry_minimal(true)` | Send the minimal telemetry payload |
|
|
869
|
+
| `set_ssl_verification(false)` | Skip TLS certificate verification (not recommended) |
|
|
870
|
+
| `set_service_url(url)` | Use another gateway URL |
|
|
871
|
+
| `set_transport(callable)` | Replace the HTTP transport (see below) |
|
|
872
|
+
|
|
873
|
+
The HTTP transport is any object that responds to `call(request)`, where `request` is a Hash with `:method`, `:url`, `:headers`, `:body`, `:timeout`, `:connect_timeout` and `:verify_ssl`, and returns a `DomainNameApi::Response` (or a Hash with `:status`, `:body`, `:headers`). The default is `DomainNameApi::NetHttpTransport` (Net::HTTP). This is how the tests run without a network:
|
|
874
|
+
|
|
875
|
+
```ruby
|
|
876
|
+
fake = ->(request) { DomainNameApi::Response.new(status: 200, body: '{"resellerId":"abc"}', headers: {}) }
|
|
877
|
+
dna = DomainNameApi::Client.new(reseller_id, api_key, false, transport: fake)
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
881
|
+
|
|
882
|
+
## Testing
|
|
883
|
+
|
|
884
|
+
The test suite uses only Minitest and never touches the network:
|
|
885
|
+
|
|
886
|
+
```bash
|
|
887
|
+
bundle install
|
|
888
|
+
bundle exec rake test
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
`test/conformance_test.rb` runs php-dna's 126 conformance fixtures (`test/fixtures/conformance/`): for each scenario it checks the requests sent (method, path, query, JSON body, auth headers) and the returned value against what php-dna produced. The other tests cover the HTTP layer, error mapping, telemetry masking, the Net::HTTP transport and the utilities.
|
|
892
|
+
|
|
893
|
+
<hr style="border: 4px solid #000; border-style: dashed;">
|
|
894
|
+
|
|
895
|
+
## Return and Error Codes with Descriptions
|
|
896
|
+
|
|
897
|
+
| Code | Description | Detail |
|
|
898
|
+
|------|------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
899
|
+
| 1000 | Command completed successfully | Operation successful. |
|
|
900
|
+
| 1001 | Command completed successfully; action pending | Operation successful. However, the operation is currently queued for completion. |
|
|
901
|
+
| 2003 | Required parameter missing | Parameter missing error. For example, no phone entry in contact information. |
|
|
902
|
+
| 2105 | Object is not eligible for renewal | Domain status is not suitable for renewal, locked for update operations. Status should not be "clientupdateprohibited". May be due to other status conditions. |
|
|
903
|
+
| 2200 | Authentication error | Authorization error, security code is incorrect or domain is registered with another registrar. |
|
|
904
|
+
| 2302 | Object exists | Domain name or nameserver information already exists in database. Cannot be registered. |
|
|
905
|
+
| 2303 | Object does not exist | Domain name or nameserver information does not exist in database. New registration required. |
|
|
906
|
+
| 2304 | Object status prohibits operation | Domain status is not suitable for updates, locked for update operations. Status should not be "clientupdateprohibited". May be due to other status conditions. |
|
|
907
|
+
|
|
908
|
+
| CODE | DETAIL |
|
|
909
|
+
|------|--------------------------------------------------------------------------------------------------------------------------------------|
|
|
910
|
+
| 101 | System Error Detailed For ({0})! |
|
|
911
|
+
| 102 | Multiple Errors Detailed For ({0})! |
|
|
912
|
+
| 103 | Unknown Errors Detailed For ({0})! |
|
|
913
|
+
| 200 | API command not found ({0})! |
|
|
914
|
+
| 210 | API service not found ({0})! |
|
|
915
|
+
| 211 | API service provider not set! |
|
|
916
|
+
| 300 | Reseller not found! |
|
|
917
|
+
| 301 | Your current IP address is not authorized to access. Please make sure you are connecting from an authorized IP address and try again |
|
|
918
|
+
| 310 | TLD is not supported! |
|
|
919
|
+
| 320 | API not found! |
|
|
920
|
+
| 321 | Currency is not supported! |
|
|
921
|
+
| 330 | Required parameter(s) not set ({0}). |
|
|
922
|
+
| – | Make sure you send all contact objects full |
|
|
923
|
+
| 340 | Price definition not found ({0}[{1}]-{2}{3}). |
|
|
924
|
+
| 350 | Insufficient reseller balance. (Reseller Id : {0} - Current Balance : {1} {2}). |
|
|
925
|
+
| 350 | Accounting currency does not match or the balance is not sufficient. |
|
|
926
|
+
| 360 | Invalid API request for field ({0}). |
|
|
927
|
+
| 360 | API quota exceeded! |
|
|
928
|
+
| 361 | Throttled error! |
|
|
929
|
+
| 362 | Premium domain is not available to register right now. |
|
|
930
|
+
| 363 | Operation cancelled because domain in auto-renewal period |
|
|
931
|
+
| 364 | This domain is currently unavailable for transaction due to a problem with the registry |
|
|
932
|
+
|
|
933
|
+
| CODE | DETAIL |
|
|
934
|
+
|------|---------------------------------------------------------------------------------------------|
|
|
935
|
+
| 400 | Invalid contact ({0}). |
|
|
936
|
+
| 401 | Contact info can not sync. |
|
|
937
|
+
| 402 | No access to contact information from registry. |
|
|
938
|
+
| 403 | THE SYSTEM HAS MISSING INFORMATION. ENTER YOUR DEFAULT INFORMATION OR CONTACT SUPPORT TEAM. |
|
|
939
|
+
| 404 | DOMAIN CONTACT CANNOT UPDATE. PERMISSION FROM THE REGISTRY. |
|
|
940
|
+
| 410 | Contact not found. |
|
|
941
|
+
| 410 | Contact not found ({0}). |
|
|
942
|
+
| 420 | Invalid Api command for contact {0}. |
|
|
943
|
+
| 430 | Contact api not found. |
|
|
944
|
+
| 440 | Contact is not synced. |
|
|
945
|
+
| 450 | Too many domain contacts! |
|
|
946
|
+
| 451 | Failed to proceed with contact update. |
|
|
947
|
+
|
|
948
|
+
| CODE | DETAIL |
|
|
949
|
+
|------|--------------------------------------------------------------------------------------------------------------------------------------|
|
|
950
|
+
| 500 | Invalid domain id. |
|
|
951
|
+
| 500 | Invalid domain id ({0}). |
|
|
952
|
+
| 501 | Domain could not synchronized({0}) |
|
|
953
|
+
| 502 | Internal transfer failed |
|
|
954
|
+
| 503 | Domain registration is not available. |
|
|
955
|
+
| 504 | Domain information does not match. Before :{0} |
|
|
956
|
+
| 505 | Enter the Ip Address. |
|
|
957
|
+
| 506 | Domain Transfer Has Been Started But Contact Info Not Read. |
|
|
958
|
+
| 507 | Authorization error. |
|
|
959
|
+
| 510 | Domain not found. |
|
|
960
|
+
| 511 | Expired domains cannot be found. |
|
|
961
|
+
| 512 | Domain is not renewable. |
|
|
962
|
+
| 513 | Domain is not in updateable status. It must be active for to be updated |
|
|
963
|
+
| 514 | Redemption Period Expected. |
|
|
964
|
+
| 520 | Invalid Api command for domain "{0}". |
|
|
965
|
+
| 530 | Invalid domain period. Period must be {0} to {1} years. Requested period is {2} years. |
|
|
966
|
+
| 540 | Domain cannot be extended beyond {0} years from current date. |
|
|
967
|
+
| 550 | Invalid domain name. Domain must be {0} to {1} characters length. Requested domain name is {2} characters. |
|
|
968
|
+
| 560 | Invalid name server count. Domain must have {0} to {1} name servers. Requested name server count is {2}. |
|
|
969
|
+
| 561 | No name server information found in the incoming request |
|
|
970
|
+
| 570 | Idn not supported for tld "{0}". |
|
|
971
|
+
| 571 | Period invalid. |
|
|
972
|
+
| 572 | Command invalid. |
|
|
973
|
+
| 573 | Domain names not found. |
|
|
974
|
+
| 574 | TLD names not found. |
|
|
975
|
+
| 575 | Domain is not in updateable status. It must be active for name servers to be updated |
|
|
976
|
+
| 576 | Domain can be renewed in the last 1 month before the expire date |
|
|
977
|
+
| 580 | Transfer not supported for tld "{0}". |
|
|
978
|
+
| 581 | Child name server not found |
|
|
979
|
+
| 582 | Transfer started by other reseller. |
|
|
980
|
+
| 583 | Transfer not initialized. Please contact the support team. |
|
|
981
|
+
| 584 | Object status prohibits operation |
|
|
982
|
+
| 590 | Auth code is required for this transfer. |
|
|
983
|
+
| 591 | Auth code is not valid. |
|
|
984
|
+
| 592 | Transfer lock exists on domain. |
|
|
985
|
+
| 593 | Domain cannot be transferred, Status Information and Transfer Lock must comply with the required criteria. (Status Information: #ok) |
|
|
986
|
+
| 594 | Domain name server address could not resolved ({0}) |
|
|
987
|
+
| 595 | Contact information can not be read (whois.registrar.tld) Please make sure that privacy protection status open |
|
|
988
|
+
| 596 | Contact information could not verified |
|
|
989
|
+
| 597 | Tld Not Found |
|
|
990
|
+
| 598 | Unknown error occurred |
|
|
991
|
+
| 599 | Domain Forward Not Found |
|
|
992
|
+
|
|
993
|
+
## License
|
|
994
|
+
|
|
995
|
+
Apache License 2.0 — see [LICENSE](LICENSE).
|