Domain API

Introduction

The Gandi Domain API provides a set of remote requests to manage your domains.

Connecting to the API server

The Gandi Domain API is provided through a set of XML-RPC calls:

>>> import xmlrpc.client
>>> api = xmlrpc.client.ServerProxy('https://rpc.gandi.net/xmlrpc/')
>>>
>>> apikey = 'my 24-character API key'
>>>
>>> # Now you can call API methods.
>>> # You must authenticate yourself by passing
>>> # the API key as the first method's argument
>>> version = api.version.info(apikey)

Note

In Python, use the xmlrpcclient module from the standard library.

<?php
// Library installed from PEAR
require_once 'XML/RPC2/Client.php';

// The first step is to connect to the API
$version_api = XML_RPC2_Client::create(
    'https://rpc.gandi.net/xmlrpc/',
    array( 'prefix' => 'version.', 'sslverify' => True )
);

// Warning !
// PEAR::XML_RPC2 checks the SSL certificate with Curl
// Curl has its own CA bundle so you may :
// * disable the 'sslverify' option: leads to security issue
// * enable the 'sslverify' option (default) and add the Gandi
// SSL certificate to the Curl bundle: best choice for security
// See: https://curl.haxx.se/docs/sslcerts.html

$apikey = 'my 24-character API key';

// Now you can call API method
// You must authenticate yourself by passing the API key
// as the first method's argument
$result = $version_api->info($apikey);

// Warning !
// PEAR::XML_RPC2 has known bugs on methods calls
// See https://pear.php.net/bugs/bug.php?id=13963
// You may use this call instead of the above one :
// $result = $version_api->__call("info", $apikey);

// dump the result
print_r($result);
?>

Note

In PHP 5, use the XML_RPC2 package from pear.

XML_RPC2 works with ‘prefix’ in order to bind to namespace. The ‘prefix’ isn’t editable, so you have to instanciante a client by namespace.

> var xmlrpc = require('xmlrpc')
> var api = xmlrpc.createSecureClient({
...  host: 'rpc.gandi.net',
...  port: 443,
...  path: '/xmlrpc/'
... })
>
> var apikey = 'my 24-character API key'
>
> // Now you can call API methods.
> // You must authenticate yourself by passing the API key
> // as the first method's argument
> api.methodCall('version.info', [apikey], function (error, value) {
...  console.dir(value)
... })

Note

With NodeJS, use the npm xmlrpc package.

use XML::RPC;

my $api = XML::RPC->new('https://rpc.gandi.net/xmlrpc/');

my $apikey = 'my 24-character API key';

# Now you can call API methods.
# You must authenticate yourself by passing the API key
# as the first method's argument
my $version = $api->call( 'version.info', $apikey );

Note

With perl, use the cpan xml::rpc package.

require 'xmlrpc/client'

server = XMLRPC::Client.new2('https://rpc.gandi.net/xmlrpc/')

apikey = 'my 24-character API key'

# Now you can call API methods.
# You must authenticate yourself by passing the API key
# as the first method's argument
version = server.call("version.info", apikey)

Note

With ruby, use the xmlrpc/client module from the standard library. Ruby does not support gzip by default, the ZlibParserDecorator is used to enabled with Ruby >1.9.

For older ruby version, neither set the http_header_extra nor the parser.

Note

To avoid RuntimeError with ruby >= 1.9, add:

XMLRPC::Config.module_eval {
    remove_const(:ENABLE_NIL_PARSER)
    const_set(:ENABLE_NIL_PARSER, true)
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <xmlrpc.h>
#include <xmlrpc_client.h>

#define CLIENT_NAME             "Documentation Client"
#define CLIENT_VERSION          "0.1"
#define CLIENT_USERAGENT        CLIENT_NAME "/" CLIENT_VERSION

#define SERVER_URL              "https://rpc.gandi.net/xmlrpc/"

int     client_connect(xmlrpc_env *);
void    client_check_fault(xmlrpc_env *);

int
main(int argc, char **argv)
{
        xmlrpc_env      env;
        xmlrpc_value    *apikey, *rv;

        client_connect(&env);

        apikey = xmlrpc_build_value(&env, "(s)", "my 24-character API key");
        rv = xmlrpc_client_call_params(&env, SERVER_URL, "version.info", apikey);
        client_check_fault(&env);

        xmlrpc_DECREF(rv);
        xmlrpc_DECREF(apikey);

        xmlrpc_env_clean(&env);
        xmlrpc_client_cleanup();

        return (0);
}

int
client_connect(xmlrpc_env *env)
{
        struct xmlrpc_clientparms clientp;
        struct xmlrpc_curl_xportparms curlp;

        curlp.network_interface = NULL;         /* use curl's default */
        curlp.ssl_verifypeer = 1;               /* Gandi API CA must be present */
        curlp.ssl_verifyhost = 2;
        curlp.user_agent = CLIENT_USERAGENT;    /* XML-RPC requirement */

        clientp.transport = "curl";
        clientp.transportparmsP = &curlp;
        clientp.transportparm_size = XMLRPC_CXPSIZE(user_agent);

        xmlrpc_env_init(env);
        xmlrpc_client_init2(env, XMLRPC_CLIENT_NO_FLAGS, CLIENT_NAME,
            CLIENT_VERSION, &clientp, XMLRPC_CPSIZE(transportparm_size));
        client_check_fault(env);

        return (1);
}

void
client_check_fault(xmlrpc_env *env)
{
        if (env->fault_occurred) {
                fprintf(stderr, "XML-RPC Fault: %s (%d)\n", env->fault_string,
                    env->fault_code);
                exit(1);
        }
}

Note

With C, use the xmlrpc-c library.

Note

the Domain API does not use HTTP authentication. It uses a custom authentication mechanism based on the API key.

Domain Creation

../_images/flowchart-domain-create.jpg

Steps to create a domain

  1. Choose a Domain name
  2. Choose or create contacts
  3. Create the domain

Choose a domain name

First, you’ll need to check the domain availability via the domain.available() method:

>>> import time
>>> domain = 'mydomain.net'
>>> result = api.domain.available(apikey, [domain])
>>> result
{'mydomain.net': 'pending'}
>>> while result[domain] == 'pending':
    time.sleep(0.7)
    result = api.domain.available(apikey, [domain])
>>> result
{'mydomain.net': 'unavailable'}
<?php
$domain = "mydomain.net";
$domain_api = XML_RPC2_Client::create(
    'https://rpc.gandi.net/xmlrpc/',
    array( 'prefix' => 'domain.' )
);
$result = $domain_api->available($apikey, array($domain));
print_r($result);
/*
Array
(
    [mydomain.net] => pending
)
*/
while ( $result[$domain] == 'pending') {
    usleep(700000);
    $result = $domain_api->available($apikey, array($domain));
}
print_r($result);
/*
Array
(
    [mydomain.net] => unavailable
)
*/
?>
> var domain = 'mydomain.net'
> var callback = function(error, value) {
...   if ( value[domain] == 'pending' ) {
...       console.log('result is not yet ready')
...       setTimeout(function() {
...           api.methodCall('domain.available', [apikey, [domain]],
...               callback)
...       }, 700)
...   }
...   else {
...      console.dir(value)
...   }
... }
> api.methodCall('domain.available', [apikey, [domain]], callback)
use Time::HiRes qw();

my $domain = 'mydomain.net';
my $result = $api->call( 'domain.available', $apikey, [$domain] );

print Data::Dumper->Dump( [$result] );
#$VAR1 = {
#    'mydomain.net' => 'pending'
#};
$api->call( 'domain.available', $apikey, [$domain] );
$result = $api->call( 'domain.available', $apikey, [$domain] );
while ($result->{$domain} eq 'pending') {
    Time::HiRes::sleep(0.7);
    $result = $api->call( 'domain.available', $apikey, [$domain] );
}
print Data::Dumper->Dump( [$result] );
#$VAR1 = {
#    'mydomain.net' => 'unavailable'
#};
domain = 'mydomain.net'
print server.call("domain.available", apikey, [domain])
{"mydomain.net"=>"pending"}
server.call("domain.available", apikey, [domain])
while result[domain] == 'pending' do
    sleep 0.7
    result = server.call("domain.available", apikey, [domain])
end
print result
{"mydomain.net"=>"unavailable"}

Note

the available method is asynchronous. You have to call it again if the result is not ready.

Choose or create contacts

You’ll need to associate your domain to an owner and 3 specific contacts: the admin, billing and technical contacts. You can choose existing contacts or, if needed, you can create new contacts, using the contact.create() (see Contact API).

Before creating your domain you can also check domain/contacts association rules with the contact.can_associate_domain() method (see How-to check domain/contact association). Use the contact.update() to correct missing or incorrect contact attributes.

>>> association_spec = {
...     'domain': 'mydomain.fr',
...     'owner': True,
...     'admin': True}
>>> api.contact.can_associate_domain(apikey, 'FLN123-GANDI',
...    association_spec)
True
>>> api.contact.can_associate_domain(apikey, 'FLN123-GANDI',
...    association_spec)
[{'error': 'EC_INVALIDPARAM1+!EC_ENUMIN',
'field': 'birth_country',
'field_type': 'Enum',
'reason': 'BirthCountryIso:  not in list ...
},... ]
<?php
$contact_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'contact.'));
$association_spec = array(
        'domain' => 'mydomain.fr',
        'owner' => true,
        'admin' => true );
print_r( $contact_api->can_associate_domain($apikey, 'FLN123-GANDI',
    $association_spec) );
// 1
// OR
print_r( $contact_api->can_associate_domain($apikey, 'FLN123-GANDI',
    $association_spec) )
/*
[{'error': 'EC_INVALIDPARAM1+!EC_ENUMIN',
        'field': 'birth_country',
        'field_type': 'Enum',
        'reason': 'BirthCountryIso:  not in list ...
},... ]
*/
?>
> var association_spec = {
...   domain: 'mydomain.fr',
...   owner: true,
...   admin: true}
> api.methodCall('contact.can_associate_domain',
...    [apikey, 'FLN123-GANDI', association_spec],
...    function (error, value) {
...        console.dir(value)
... })
my $association_spec = {
    'domain' => 'mydomain.fr',
    'owner' => True,
    'admin' => True
};
my $result = $api->call( 'contact.can_associate_domain', $apikey,
    'FLN123-GANDI', $association_spec );
print $result;
True
$result = $api->call( 'contact.can_associate_domain', $apikey,
    'FLN123-GANDI', $association_spec );
print $result;
[{'error': 'EC_INVALIDPARAM1+!EC_ENUMIN',
'field': 'birth_country',
'field_type': 'Enum',
'reason': 'BirthCountryIso:  not in list ...'
} #,...
]
association_spec = {
    'domain' => 'mydomain.fr',
    'owner'=> true,
    'admin'=> true
}
print server.call("contact.can_associate_domain", apikey, 'FLN123-GANDI',
    association_spec)
True
print server.call("contact.can_associate_domain", apikey, 'FLN123-GANDI',
    association_spec)
[{'error': 'EC_INVALIDPARAM1+!EC_ENUMIN',
'field': 'birth_country',
'field_type': 'Enum',
'reason': 'BirthCountryIso:  not in list ...'
}, #...
]

Create the domain

To create your domain use domain.create()

>>> domain_spec = {
...     'owner': 'FLN123-GANDI',
...     'admin': 'FLN123-GANDI',
...     'bill': 'FLN123-GANDI',
...     'tech': 'FLN123-GANDI',
...     'nameservers': ['a.dns.gandi-ote.net', 'b.dns.gandi-ote.net',
...                     'c.dns.gandi-ote.net'],
...     'duration': 1}
>>> op = api.domain.create(apikey, 'mydomain.net', domain_spec)
<?php
$domain_spec = array(
    'owner' => 'FLN123-GANDI',
    'admin' => 'FLN123-GANDI',
    'bill' => 'FLN123-GANDI',
    'tech' =>'FLN123-GANDI',
    'nameservers' => array('a.dns.gandi-ote.net', 'b.dns.gandi-ote.net',
                           'c.dns.gandi-ote.net'),
    'duration' => 1);
$op = $domain_api->__call('create', array($apikey, 'mydomain.net',
    $domain_spec));
?>

Note

$domain_api->__call(“create”,…) calls the rpc method domain.create()

see bug #13963 : RPC method named create can’t be called by client.

> var domain_spec = {
...   owner: 'FLN123-GANDI',
...   admin: 'FLN123-GANDI',
...   bill: 'FLN123-GANDI',
...   tech: 'FLN123-GANDI',
...   nameservers: ['a.dns.gandi-ote.net', 'b.dns.gandi-ote.net',
...                 'c.dns.gandi-ote.net'],
...   duration: 1
... }
> api.methodCall('domain.create', [apikey, 'mydomain.net', domain_spec],
...   function (error, value) {
...     console.dir(value)
...   })
my $domain_spec = {
    owner => 'FLN123-GANDI',
    admin => 'FLN123-GANDI',
    bill => 'FLN123-GANDI',
    tech => 'FLN123-GANDI',
    nameservers => ['a.dns.gandi-ote.net', 'b.dns.gandi-ote.net',
                    'c.dns.gandi-ote.net'],
    duration => 1,
};
my $op = $api->call( 'domain.create', $apikey, 'mydomain.net',
    $domain_spec);
domain_spec = {
    'owner' => 'FLN123-GANDI',
    'admin' => 'FLN123-GANDI',
    'bill' => 'FLN123-GANDI',
    'tech' => 'FLN123-GANDI',
    'nameservers' => ['a.dns.gandi-ote.net', 'b.dns.gandi-ote.net',
                      'c.dns.gandi-ote.net'],
    'duration' => 1}
op = server.call("domain.create", apikey, 'mydomain.net', domain_spec)

domain.create() takes the domain name as the first argument and the domain specification as its second argument. The domain specification provides the owner, admin, tech and bill contacts, the nameservers and the duration (in years) of your domain. When you ask for a domain creation, the domain will not be immediately available. You can track the process state by calling operation.info().

>>> op = api.operation.info(apikey, op['id'])
>>> op['step']
'BILL'
>>> op = api.operation.info(apikey, op['id'])
>>> op['step']
'DONE'
<?php
$op = $operation_api->info($apikey, $op['id'])
echo $op['step']
//'BILL'

// and later...
$op = $operation_api->info($apikey, $op['id'])
echo $op['step']
//'DONE'
?>

Note

XML_RPC2 works with ‘prefix’ in order to represent object notation.

> client.methodCall( 'operation.info', [apikey, op['id']],
...  function(err, value) {
...      console.log(value.step)
...      // output 'BILL'
...      // but later, will print 'DONE'
...  })
my $operation = $api->call( 'operation.info', $apikey, $op->{'id'} );
print $operation->{'step'};
'BILL'
$operation = $api->call( 'operation.info', $apikey, $op->{'id'} );
print $operation->{'step'};
'DONE'
op = server.call("operation.info", apikey, op{'id'})
print op['step']
'BILL'
op = server.call("operation.info", apikey, op{'id'})
print op['step']
'DONE'

Domain Management

Get Information

To get information, you can use the list, count, and info methods on the domain namespace.

>>> api.domain.info(apikey, 'mydomain.net')
{'authinfo': 'xxx',
'contacts': {'admin': {'handle': 'FLN123-GANDI', 'id': 12345},
    'bill': {'handle': 'FLN123-GANDI', 'id': 12345},
    'tech': {'handle': 'FLN123-GANDI', 'id': 12345},
    'admin': {'handle': 'FLN123-GANDI', 'id': 12345},
    'owner': {'handle': 'FLN123-GANDI', 'id': 12345},
    'reseller': {'handle': 'FLN123-GANDI', 'id': 12345},
    },
 'tld': 'com',
 'date_created': <DateTime '20110304T16:48:17' at 8d1072c>,
 'date_updated': <DateTime '20110506T15:34:17' at 8d1072c>,
 'date_registry_end': <DateTime '20120304T16:48:17' at 8d1072c>,
 'fqdn': 'mydomain.net',
 'id': 123,
 'nameservers': ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
 'status': ['TransferProhibited'],
 'tags': ['a', 'b', 'c'],
 'zone_id': 42}
<?php
print_r($domain_api->info($apikey, 'mydomain.net'));
/*
Array
(
    [status] => Array
        (
            [0] => clientTransferProhibited
        )

    [zone_id] => 42
    [contacts] => Array
        (
            [owner] => Array
                (
                    [handle] => FLN123-GANDI
                    [id] => 12345
                )

            [admin] => Array
                (
                    [handle] => FLN123-GANDI
                    [id] => 12345
                )

            [bill] => Array
                (
                    [handle] => FLN123-GANDI
                    [id] => 12345
                )

            [tech] => Array
                (
                    [handle] => FLN123-GANDI
                    [id] => 12345
                )

            [reseller] =>
        )

    [date_updated] => stdClass Object
        (
            [scalar] => 20110902T18:27:34
            [timestamp] => 1314980854
            [xmlrpc_type] => datetime
        )

    [date_registry_end] => stdClass Object
        (
            [scalar] => 20120902T16:27:33
            [timestamp] => 1346596053
            [xmlrpc_type] => datetime
        )

    [tags] => Array
        (
        )

    [fqdn] => mydomain.net
    [nameservers] => Array
        (
            [0] => a.dns.gandi.net
            [1] => b.dns.gandi.net
            [2] => c.dns.gandi.net
        )

    [authinfo] => xxx
    [tld] => com
    [date_created] => stdClass Object
        (
            [scalar] => 20110902T16:27:34
            [timestamp] => 1314973654
            [xmlrpc_type] => datetime
        )

    [id] => 123
)


*/

Note

XML_RPC2 works with a ‘prefix’ in order to bind to namespace. The ‘prefix’ isn’t editable, so you have to instanciante a client by namespace

> api.methodCall('domain.info', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
{ status: [ 'clientTransferProhibited' ],
zone_id: 42,
contacts:
{ owner: { handle: 'FLN123-GANDI', id: 1002336 },
 admin: { handle: 'FLN123-GANDI', id: 1002336 },
 bill: { handle: 'FLN123-GANDI', id: 1002336 },
 tech: { handle: 'FLN123-GANDI', id: 1002336 },
 reseller: '' },
date_updated: Fri, 02 Sep 2011 16:27:34 GMT,
date_registry_end: Sun, 02 Sep 2012 14:27:33 GMT,
tags: [],
fqdn: 'mydomain.net',
nameservers: [ 'a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net' ],
authinfo: 'A3SB9$9j8u',
tld: 'com',
date_created: Fri, 02 Sep 2011 14:27:34 GMT,
id: 2049696 }
my $result = $api->call( 'domain.info', $apikey, 'mydomain.net' );
print Data::Dumper->Dump( [$result] );
#$VAR1 = { 'authinfo' => 'xxx',
#'contacts' => {'admin' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    'bill' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    'tech' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    'admin' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    'owner' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    'reseller' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
#    },
# 'tld' => 'com',
# 'date_created' => '20110304T16:48:17',
# 'date_updated' => '20110506T15:34:17',
# 'date_registry_end' => '20120304T16:48:17',
# 'fqdn' => 'mydomain.net',
# 'id' => 123,
# 'nameservers' => ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
# 'status' => ['TransferProhibited'],
# 'tags' => ['a', 'b', 'c'],
# 'zoneid' => 42};
print server.call("domain.info", apikey, 'mydomain.net')
{'authinfo' => 'xxx',
'contacts' => {'admin' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    'bill' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    'tech' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    'admin' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    'owner' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    'reseller' => {'handle' => 'FLN123-GANDI', 'id' => 12345},
    },
 'tld' => 'com',
 'date_created' => #<XMLRPC::DateTime:0x00000001f58970 @year=2011,
 ... @month=3, @day=4, @hour=16, @min=48, @sec=17>,
 'date_updated' => #<XMLRPC::DateTime:0x00000001f58970 @year=2011,
 ... @month=5, @day=6, @hour=15, @min=34, @sec=17>,
 'date_registry_end' => #<XMLRPC::DateTime:0x00000001f58970 @year=2012,
 ... @month=3, @day=4, @hour=16, @min=48, @sec=17>,
 'fqdn' => 'mydomain.net',
 'id' => 123,
 'nameservers' => ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
 'status' => ['TransferProhibited'],
 'tags' => ['a', 'b', 'c'],
 'zone_id' => 42}

You can use the following domain namespaces if you need to retrieve more data:

For each namespace, the info/list/count methods are available.

Getting domain host information:

>>> api.domain.host.list(apikey, 'mydomain.net')
>>> api.domain.host.count(apikey, 'mydomain.net')
>>> api.domain.host.info(apikey, 'www.mydomain.net')
<?php
$domain_host_api = XML_RPC2_Client::create($api_uri,
  array('prefix' => 'domain.host.'));
$domain_host_api->list($apikey, 'mydomain.net');
$domain_host_api->count($apikey, 'mydomain.net');
$domain_host_api->info($apikey, 'mydomain.net');
?>
> api.methodCall('domain.host.list', [apikey, 'mydomain.net'],
... function (error, value) {
...    console.dir(value)
... })
> api.methodCall('domain.host.count', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
> api.methodCall('domain.host.info', [apikey, 'www.mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
$api->call( 'domain.host.list', $apikey, 'mydomain.net' );
$api->call( 'domain.host.count', $apikey, 'mydomain.net' );
$api->call( 'domain.host.info', $apikey, 'www.mydomain.net' );
server.call("domain.host.list", apikey, 'mydomain.net')
server.call("domain.host.count", apikey, 'mydomain.net')
server.call("domain.host.info", apikey, 'www.mydomain.net')

Getting domain web redirection information:

>>> api.domain.webredir.list(apikey, 'mydomain.net')
>>> api.domain.webredir.count(apikey, 'mydomain.net')
>>> api.domain.webredir.info(apikey, 'mydomain.net')
<?php
$domain_webredir_api = XML_RPC2_Client::create($api_uri,
  array('prefix' => 'domain.webredir.'));
$domain_webredir_api->list($apikey, 'mydomain.net');
$domain_webredir_api->count($apikey, 'mydomain.net');
$domain_webredir_api->info($apikey, 'mydomain.net');
?>
> api.methodCall('domain.webredir.list', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
> api.methodCall('domain.webredir.count', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
> api.methodCall('domain.webredir.info', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
$api->call( 'domain.webredir.list', $apikey, 'mydomain.net' );
$api->call( 'domain.webredir.count', $apikey, 'mydomain.net' );
$api->call( 'domain.webredir.info', $apikey, 'mydomain.net' );
server.call("domain.webredir.list", apikey, 'mydomain.net')
server.call("domain.webredir.count", apikey, 'mydomain.net')
server.call("domain.webredir.info", apikey, 'mydomain.net')

Getting domain mailbox information:

>>> api.domain.mailbox.list(apikey, 'mydomain.net')
[{'login': 'admin'}]
>>> api.domain.mailbox.count(apikey, 'mydomain.net')
1
>>> api.domain.mailbox.info(apikey, 'mydomain.net', 'admin')
<?php
$domain_mailbox_api = XML_RPC2_Client::create($api_uri,
  array('prefix' => 'domain.mailbox.'));
$domain_mailbox_api->list($apikey, 'mydomain.net');
/*
Array ( [login] => 'admin' )
*/
$domain_mailbox_api->count($apikey, 'mydomain.net');
/*
 1
*/
$domain_mailbox_api->info($apikey, 'mydomain.net');
?>
> api.methodCall('domain.mailbox.list', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
[{'login': 'admin'}]
> api.methodCall('domain.mailbox.count', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... })
1
> api.methodCall('domain.mailbox.info', [apikey, 'mydomain.net'],
... function (error, value) {
...     console.dir(value)
... }])
$api->call( 'api.domain.mailbox.list', $apikey, 'mydomain.net' );
[{'login' => 'admin'}]
$api->call( 'domain.mailbox.count', $apikey, 'mydomain.net' );
1
$api->call( 'domain.mailbox.info', $apikey, 'mydomain.net', 'admin' );
server.call("domain.mailbox.list", apikey, 'mydomain.net')
[{'login' => 'admin'}]
server.call("domain.mailbox.count", apikey, 'mydomain.net')
1
server.call("domain.mailbox.info", apikey, 'mydomain.net', 'admin')

Getting domain forwarding information:

>>> api.domain.forward.count(apikey, 'mydomain.net')
1
>>> api.domain.forward.list(apikey, 'mydomain.net')
[{'destinations': ['stephanie@example.com'], 'source': 'admin'}]
<?php
$domain_webredir_api = XML_RPC2_Client::create($api_uri,
  array('prefix' => 'domain.forward.'));
$domain_forward_api->count($apikey, 'mydomain.net');
//1
$domain_forward_api->list($apikey, 'mydomain.net');
/*
Array
  (
      Array
          (
              [destinations] => Array('stephanie@example.com')
              [source] => 'admin'
          )
  )
*/
?>
> api.methodCall('domain.forward.count', [apikey, 'mydomain.net'],
... function (error, value) {
...   console.dir(value)
... })
1
> api.methodCall('api.domain.forward.list', [apikey, 'mydomain.net'],
... function (error, value) {
...   console.dir(value)
... })
[{destinations: ['stephanie@example.com'], source: 'admin'}]
my $result = $api->call( 'domain.forward.count', $apikey, 'mydomain.net' );
print $result;
1
$result = $api->call( 'domain.forward.list', $apikey, 'mydomain.net' );
print Data::Dumper->Dump( [$result] );
#[{'destinations' => ['stephanie@example.com'], 'source' => 'admin'}]
server.call("domain.forward.count", apikey, 'mydomain.net')
1
server.call("domain.forward.list", apikey, 'mydomain.net')
[{'destinations' => ['stephanie@example.com'], 'source' => 'admin'}]

Update a domain

The following attributes can be set/updated:

For each attribute you can perform the following actions.

Updating domain contacts:

>>> contacts_spec = {
...     'admin': 'FLN123-GANDI',
...     'tech': 'FLN123-GANDI',
...     'bill': 'FLN123-GANDI'}
>>> api.domain.contacts.set(apikey, 'mydomain.net', contacts_spec)
<?php
$domain_contacts_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.contacts.'));
contacts_spec = array(
    'admin' => 'FLN123-GANDI',
    'tech' => 'FLN123-GANDI',
    'bill'=> 'FLN123-GANDI'
);
$domain_contacts_api->set($apikey, 'mydomain.net', $contacts_spec);
?>
> contacts_spec = {
...  'admin': 'FLN123-GANDI',
...  'tech': 'FLN123-GANDI',
...  'bill': 'FLN123-GANDI'}
> api.methodCall('domain.contacts.set',
... [apikey, 'mydomain.net', contacts_spec],
... function (error, value) {
...    console.dir(value)
... })
my $contacts_spec = {
  admin => 'FLN123-GANDI',
  tech => 'FLN123-GANDI',
  bill => 'FLN123-GANDI'
};
$api->call( 'domain.contacts.set', $apikey, 'mydomain.net', $contacts_spec);
contacts_spec = {
  'admin' => 'FLN123-GANDI',
  'tech' => 'FLN123-GANDI',
  'bill' => 'FLN123-GANDI'}
server.call("domain.contacts.set", apikey, 'mydomain.net', contacts_spec)

(Un)Setting the lock transfer on your domain:

>>> api.domain.status.lock(apikey, 'mydomain.net')
>>> api.domain.status.unlock(apikey, 'mydomain.net')
<?php
$domain_status_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.status.'));
$domain_status_api->lock($apikey, 'mydomain.net');
$domain_status_api->unlock($apikey, 'mydomain.net');
?>
> api.methodCall('domain.status.lock', [apikey, 'mydomain.net'],
... function (error, value) {
...    console.dir(value)
... })
> api.methodCall('domain.status.unlock', [apikey, 'mydomain.net'],
... function (error, value) {
...    console.dir(value)
... })
$api->call( 'domain.status.lock', $apikey, 'mydomain.net' );
$api->call( 'domain.status.unlock', $apikey, 'mydomain.net' );
server.call("domain.status.lock", apikey, 'mydomain.net')
server.call("domain.status.unlock", apikey, 'mydomain.net')

Updating the domain nameservers:

>>> api.domain.nameservers.set(apikey, 'mydomain.net', \
    ['a.dns.mydomain.net', 'b.dns.mydomain.net', 'c.dns.mydomain.net'])
<?php
$domain_nameservers_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.nameservers.'));
$domain_nameservers_api->set($apikey, 'mydomain.net',
    array('a.dns.mydomain.net', 'b.dns.mydomain.net', 'c.dns.mydomain.net'));
?>
> api.methodCall('domain.nameservers.set', 'mydomain.net',
    ['a.dns.mydomain.net', 'b.dns.mydomain.net', 'c.dns.mydomain.net'])
... function (error, value) {
...    console.dir(value)
... })
$api->call( 'domain.nameservers.set', $apikey, 'mydomain.net',
    ['a.dns.mydomain.net', 'b.dns.mydomain.net', 'c.dns.mydomain.net'] );
server.call("domain.nameservers.set", apikey, 'mydomain.net',
    ['a.dns.mydomain.net', 'b.dns.mydomain.net', 'c.dns.mydomain.net'])

The following domain namespaces are available:

For each namespace, the create/delete/set/update methods are available.

Managing domain host:

>>> api.domain.host.create(apikey, 'dns1.mydomain.net', ['1.2.3.4'])
>>> api.domain.host.delete(apikey, 'dns1.mydomain.net')
$domain_host_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.host.'));
<?php
$domain_host_api->create($apikey, 'dns1.mydomain.net', array('1.2.3.4'));
$domain_host_api->delete($apikey, 'dns1.mydomain.net');
?>
> api.methodCall('domain.host.create', [apikey, 'dns1.mydomain.net',
... ['1.2.3.4']],
... function (error, value) {
...  console.dir(value)
... })
> api.methodCall('domain.host.delete', [apikey, 'dns1.mydomain.net'],
... function (error, value) {
...  console.dir(value)
... })
$api->call( 'domain.host.create', $apikey, 'dns1.mydomain.net', ['1.2.3.4'] );
$api->call( 'domain.host.delete', $apikey, 'dns1.mydomain.net' );
server.call("domain.host.create", apikey, 'dns1.mydomain.net', ['1.2.3.4'])
server.call("domain.host.delete", apikey, 'dns1.mydomain.net')

Managing domain web redirections. For example, redirecting your domain only to www:

>>> webredir_specs = {
...     'host': '',
...     'url': "http://www.mydomain.net"}
>>> api.domain.webredir.create(apikey, "mydomain.net", webredir_specs)
{'host': '',
 'url': 'http://www.mydomain.net',
 'type': 'http302'}
<?php
webredir_specs = array(
  'host' => '',
  'url' => "http://www.mydomain.net"
);

print_r($domain_webredir_api->__call('create',
    array($apikey, "mydomain.net", $webredir_specs)));
/*
Array
    (
        [host]: '',
        [url]: 'http://www.mydomain.net',
        [type]: 'http302'
    )
*/
?>
> var webredir_specs = {
...   'host' : '',
...   'url' : "http://www.mydomain.net"}
... }
> api.methodCall('domain.webredir.create',
... [apikey,"mydomain.net", webredir_specs],
... function (error, value) {
...  console.dir(value)
... })
{host: '',
 url: 'http://www.mydomain.net',
 type: 'http302'}
$webredir_specs = {
    'host' => '',
    'url' => "http://www.mydomain.net",
};
my $result = $api->call( 'domain.webredir.create', $apikey,
    'mydomain.net', $webredir_specs );
print Data::Dumper->Dump( [$result] );
#$VAR1 = {'host' => '',
# 'url' => 'http://www.mydomain.net',
# 'type' => 'http302'
#};
webredir_specs = {
    'host' => '',
    'url' => "http://www.mydomain.net"
}
server.call("domain.webredir.create", apikey,
    "mydomain.net",webredir_specs)
{'host' => '',
 'url' => 'http://www.mydomain.net',
 'type' => 'http302'}

Note

The type defaults to http302 if not specified

Managing domain mailboxes:

>>> api.domain.mailbox.create(apikey, 'mydomain.net', 'admin',
... {'password': 'xxxxxx'})
>>> api.domain.mailbox.alias.set(apikey, 'mydomain.net', 'admin', ['stephanie'])
>>> api.domain.mailbox.delete(apikey, 'mydomain.net', 'admin')
<?php
$domain_mailbox_api->__call('create', array($apikey, 'mydomain.net', 'admin',
... array('password' => 'xxxxxx')));
$domain_mailbox_api->mailbox.aliases.set($apikey, 'mydomain.net', 'admin',
... array('stephanie'));
$domain_mailbox_api->mailbox.delete($apikey, 'mydomain.net', 'admin');
?>
> api.methodCall('domain.mailbox.create', [apikey, 'mydomain.net',
... 'admin', {'password' : 'xxxxxx'}],
... function (error, value) {
...  console.dir(value)
... })

> api.methodCall('domain.mailbox.aliases.set',
... [apikey, 'mydomain.net', 'admin', ['stephanie']],
... function (error, value) {
...  console.dir(value)
... })

> api.methodCall('domain.mailbox.aliases.delete',
... [apikey, 'mydomain.net', 'admin'],
... function (error, value) {
...  console.dir(value)
... })
$api->call( 'domain.mailbox.create', $apikey, 'mydomain.net', 'admin',
    {'password' : 'xxxxxx'} );
$api->call( 'domain.mailbox.aliases.set', $apikey, 'mydomain.net', 'admin',
    ['stephanie'] );
$api->call( 'domain.mailbox.delete', $apikey, 'mydomain.net', 'admin' );
server.call("domain.mailbox.create", apikey, 'mydomain.net', 'admin',
    {'password' => 'xxxxxx'})
server.call("domain.mailbox.aliases.set", apikey, 'mydomain.net', 'admin',
    ['stephanie'])
server.call("domain.mailbox.delete", apikey, 'mydomain.net', 'admin')

Managing domain forwards:

>>> api.domain.forward.create(apikey, 'mydomain.net', 'admin',
... {'destinations': ['stephanie@example.com']})
{'destinations': ['stephanie@example.com'], 'source': 'admin'}

>>> api.domain.forward.update(apikey, 'mydomain.net', 'admin',
... {'destinations': ['stephanie@example.com', 'steph@example.com']})
{'destinations': ['stephanie@example.com', 'steph@example.com'], 'source': 'admin'}

>>> api.domain.forward.delete(apikey, 'mydomain.net', 'admin')
True
<?php
print_r($domain_forward_api->__call('create',
    array($apikey, 'mydomain.net', 'admin',
        array('destinations'=> array('stephanie@example.com')))));
/*
Array
    (
        [destinations] => Array ( 'stephanie@example.com' )
        [source] => 'admin'
    )
*/
print_r($domain_forward_api->update($apikey, 'mydomain.com', 'admin',
    array('destinations'=> array('stephanie@example.com', 'steph@example.com'))));
/*
Array
    (
        [destinations] => Array( 'stephanie@example.com', 'steph@example.com'),
        [source]: 'admin'
    )
*/
print_r($domain_api->forward.delete($apikey, 'mydomain.com', 'admin'));
// true
?>
> api.methodCall('domain.forward.create', [apikey, 'mydomain.net', 'admin',
... {'destinations': ['stephanie@example.com']}],
... function (error, value) {
...  console.dir(value)
... })
{destinations: ['stephanie@example.com'], source: 'admin'}

> api.methodCall('domain.forward.create', [apikey, 'mydomain.net', 'admin',
... {'destinations': ['stephanie@example.com', 'steph@example.com']}],
... function (error, value) {
...  console.dir(value)
... })
{destinations: ['stephanie@example.com', 'steph@example.com'], source: 'admin'}

> api.methodCall('domain.forward.update', [ apikey, 'mydomain.net',
... ['admin', {destinations: ['stephanie@example.com', 'steph@example.com']}],
... function (error, value) {
...  console.dir(value)
... })
{destinations: ['stephanie@example.com', 'steph@example.com'], source: 'toto'}

> api.methodCall('domain.forward.delete', [ apikey, 'mydomain.net', 'admin' ] )
True
$api->call( 'domain.forward.create', $apikey, 'mydomain.net', 'admin',
  {'destinations' => ['stephanie@example.com']} );
{'destinations' => ['stephanie@example.com'], 'source' => 'admin'}

$result = $api->call( 'domain.forward.update', $apikey, 'mydomain.net',
  'admin', {'destinations' => ['stephanie@example.com', 'steph@example.com']} );
{'destinations' => ['stephanie@example.com', 'steph@example.com'], 'source' => 'admin'}

$api->call( 'domain.available', $apikey, 'mydomain.net', 'admin' );
True
server.call("domain.forward.create", apikey, 'mydomain.net', 'admin',
  {'destinations' => ['stephanie@example.com']})
{'destinations' => ['stephanie@example.com'], 'source': 'admin'}

server.call("domain.forward.update", apikey, 'mydomain.net', 'admin',
  {'destinations' => ['stephanie@example.com', 'steph@example.com']})
{'destinations' => ['stephanie@example.com', 'steph@example.com'],
... 'source' => 'admin'}

server.call("domain.forward.delete", apikey, 'mydomain.net', 'admin')
True

This method allows to reset a domain authinfo code at the registry:

>>> api.domain.reset_authinfo(apikey, 'mydomain.net')

Domain Processing

Renew a domain

../_images/flowchart-domain-renew.jpg
>>> renew_spec = {
...     'duration': 1,
...     'current_year': 2011}
>>> api.domain.renew(apikey, 'mydomain.net', renew_spec)
<?php
$renew_spec = array(
  'duration'=> 1,
  'current_year'=> 2011);
$domain_api->renew($apikey, 'mydomain.net', $renew_spec);
?>
> renew_spec = {
...     'duration': 1,
...     'current_year': 2011}
> api.methodCall('domain.renew', [apikey, 'mydomain.net'],
... function (error, value) {
...  console.dir(value)
... })
$renew_spec = {
    'duration' => 1,
    'current_year' => 2011
};
$api->call( 'domain.renew', $apikey, 'mydomain.net', $renew_spec );
renew_spec = {
    'duration' => 1,
    'current_year' => 2011}
server.call("domain.renew", apikey, 'mydomain.net', renew_spec)

Note

The current_year parameter means the current expiration date of the domain.

Transfer a domain to Gandi

Transfer workflow

../_images/flowchart-domain-transfer.jpg

Check Transfer availability

In order to check if a domain is available for Transfer you may want to use the api.domain.transferin.available method.

The values this method returns can be quite different one from another when querying several domains and we will explain them here.

This method raises an Exception when it encounters specific cases which prevent a Transfer from occuring:

  • transfer_availability_error if the command is called with a domain which TLD is - or will be soon - discontinued
  • transfer_availability_eoi when the TLD is still in the Expression of Interest phase
  • transfer_availability_error if the domain contains a SLD we do not support or does not exist (ie: gandi.org.com)
  • transfer_availability_error if called with an IDN domain on a TLD which do not support IDN
  • reserved_corporate if called by a User without a Corporate Account on a TLD requiring a Corporate Account
  • domain_is_restorable if the domain is currently in the restore period
  • transfer_prohibited if the API could query the registry and the statuses of the domain currently prevent any Transfer

When the API can not query the registry - for a variety of reasons - we have chosen to return True. You can then try to launch the transfer and see if it succeeds.

When the API manages to query the registry it will return a dictionnary with data about the domain, in this case you may be quite sure about the domain transferability.

Note

api.domain.transferin.available is not a method to validate the authinfo code. The only way to really validate an authinfo code is to start the transfer.

Proceed to a new Transfer

>>> transfer_spec = {
...     'owner': 'FLN123-GANDI',
...     'admin': 'FLN123-GANDI',
...     'tech': 'FLN123-GANDI',
...     'bill': 'FLN123-GANDI',
...     'nameservers': ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
...     'authinfo': 'xxx',
...     'duration': 1}
>>> api.domain.transferin.proceed(apikey, 'mydomain.net', transfer_spec)
<?php
$domain_transferin_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.transferin.'));
$transfer_spec = array(
  'owner' => 'FLN123-GANDI',
  'admin' => 'FLN123-GANDI',
  'tech' => 'FLN123-GANDI',
  'bill' => 'FLN123-GANDI',
  'nameservers' => array('a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'),
  'authinfo' => 'xxx',
  'duration' => 1)
$domain_transferin_api->proceed($apikey, 'mydomain.net', transfer_spec);
?>
> var transfer_spec = {
>     owner: 'FLN123-GANDI',
>     admin: 'FLN123-GANDI',
>     tech: 'FLN123-GANDI',
>     bill: 'FLN123-GANDI',
>     nameservers: ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
>     authinfo: 'xxx',
>     duration: 1}
> api.methodCall('domain.transferin.proceed', [apikey, 'mydomain.net',
... transfer_spec],
... function (error, value) {
...  console.dir(value)
... })
$transfer_spec = {
    owner => 'FLN123-GANDI',
    admin => 'FLN123-GANDI',
    tech => 'FLN123-GANDI',
    bill => 'FLN123-GANDI',
    nameservers => ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
    authinfo => 'xxx',
    duration => 1
};
$api->call( 'domain.transferin.proceed', $apikey, 'mydomain.net', $transfer_spec );
transfer_spec = {
    'owner' => 'FLN123-GANDI',
    'admin' => 'FLN123-GANDI',
    'tech' => 'FLN123-GANDI',
    'bill' => 'FLN123-GANDI',
    'nameservers' => ['a.dns.gandi.net', 'b.dns.gandi.net', 'c.dns.gandi.net'],
    'authinfo' => 'xxx',
    'duration' => 1}
server.call("domain.transferin.proceed", apikey, 'mydomain.net', transfer_spec)

Send Transfer confirmation mails again

If you have requested a Transfer but see that the email address to which the confirmation email has been sent is wrong, for example the owner of a non-GTLD domain has an expired email address declared on the WHOIS record, you will be able to restart a domain transfer operation once the WHOIS records have been updated by calling the domain.transferin.resend_foa API method.

>>> api.domain.transferin.resend_foa(apikey, 'mydomain.net')

Note

Due to registry limitations, you can create a transfer operation in OTE, but the command will fail at the registry.

Update a bad authinfo code

Let’s say that you made an error when entering the authinfo code of a Transfer operation and that the Transfer was rejected by the registrar. You can call this method to update the authinfo and restart the Transfer by calling the domain.transferin.update_authinfo API method.

>>> api.domain.transferin.update_authinfo(apikey, 'mydomain.net', 'new_auth')

Note

This method will restart and update the latest Transfer operation in error for the given domain with your handle as source of the operation.

Restore a domain

>>> restore_spec = {
...     'duration': 1}
>>> api.domain.restore(apikey, 'mydomain.net', restore_spec)
<?php
$restore_spec = array(
  'duration'=> 1);
$domain_api->restore($apikey, 'mydomain.net', $restore_spec);
?>
> restore_spec = {
...     'duration': 1}
> api.methodCall('domain.restore', [apikey, 'mydomain.net'],
... function (error, value) {
...  console.dir(value)
... })
$restore_spec = {
    'duration' => 1
};
$api->call( 'domain.restore', $apikey, 'mydomain.net', $restore_spec );
restore_spec = {
    'duration' => 1}
server.call("domain.restore", apikey, 'mydomain.net', restore_spec)

Note

Due to registry limitations, you can create a restore operation in OTE, but the command will fail at the registry.

Delete a domain

../_images/flowchart-domain-delete.jpg

Note

The domain deletion is currently a restricted feature.

TLD

List all TLDs available in API

>>> api.domain.tld.list(apikey)
<?php
$domain_api = XML_RPC2_Client::create($api_uri, array('prefix' => 'domain.tld.'));
$domain_api->list($apikey);
?>
> api.methodCall('domain.tld.list', [apikey],
... function (error, value) {
...  console.dir(value)
... })
$api->call( 'domain.tld.list', $apikey );
server.call("domain.tld.list", apikey)

List all TLDs by region, available in API

>>> api.domain.tld.region(apikey)
<?php
$domain_api = XML_RPC2_Client::create($api_uri,
    array('prefix' => 'domain.tld.'));
$domain_api->region($apikey);
?>
> api.methodCall('domain.tld.region', [apikey],
... function (error, value) {
...  console.dir(value)
... })
$api->call( 'domain.tld.region', $apikey );
server.call("domain.tld.region", apikey)

Domain price list

In order to get a more precise pricing of multiple fqdn and process, the domain.price.list() method has been added. However this is an async method which can respond a pending availability, in which case you have to repeat the call until full result is ready. Here’s a sample python call and result :

>>> api.domain.price.list(api_key, {'tlds': ['testdomain.net'], 'action': ['create', 'renew']})

[{'available': 'pending', 'current_phase': 'golive', 'errors': [], 'extension': 'testdomain.net', 'idn_lang': True, 'name': 'net', 'phases': [{'date_end': None, 'date_start': <DateTime '19990521T00:00:00' at 7f0090110290>, 'date_start_gandi': <DateTime '19990521T00:00:00' at 7f00901102d8>,'phase': 'golive'}], 'prices': [], 'provided': False, 'region': 'generic', 'subdomains': [], 'visibility': 'all'}]

>>> api.domain.price.list(api_key, {'tlds': ['testdomain.net'], 'action': ['create', 'renew']})

[{'available': 'unavailable', 'provided': False, 'phases': [{'phase': 'golive', 'date_end': None, 'date_start': <DateTime '19990521T00:00:00' at 7f07a5e14ef0>, 'date_start_gandi': <DateTime '19990521T00:00:00' at 7f07a5e14fc8>}], 'errors': [], 'name': 'net', 'extension': 'testdomain.net', 'region': 'generic', 'visibility': 'all', 'subdomains': [], 'idn_lang': True, 'prices': [{'action': {'name': 'renew', 'param': {}}, 'product': {'type': 'domain', 'description': '.net'}, 'taxes': {'rate': 17.0, 'type': 'service', 'name': 'vat'}, 'unit_price': [{'max_duration': 9, 'special_op': False, 'duration_unit': 'y', 'price': 17.0, 'price_type': None, 'min_duration': 1, 'currency': 'EUR', 'grid': 'A', 'id': 655514}]}], 'current_phase': 'golive'}]