├── README.md ├── bash └── livedns │ └── mywanip.sh ├── php ├── catalog │ └── price-promo-by-tld.php └── domain │ └── price-list │ └── DomainPrice.php └── python └── domain ├── contactsundermgnt.py └── price ├── domain-price.py └── simple-calls.py /README.md: -------------------------------------------------------------------------------- 1 | # API Examples 2 | Scripts and snippets of code for using the Gandi API with any programming language. 3 | 4 | Full reference documentation of the Gandi API is available at http://doc.rpc.gandi.net/ . 5 | 6 | Also Gandi CLI (an open source command line interface written in Python) which interfaces with Gandi's API is available here: https://github.com/Gandi/gandi.cli 7 | -------------------------------------------------------------------------------- /bash/livedns/mywanip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Updates a zone record using Gandi's LiveDNS. 4 | # Ideally this script is placed into a crontab or when the WAN interface comes up. 5 | # Replace APIKEY with your Gandi API Key and DOMAIN with your domain name at Gandi. 6 | # Set RECORD to which zone label you wish to update. 7 | # You will be able to query mywanip.example.net if everything went successful. 8 | # 9 | # Live dns is available on www.gandi.net 10 | # Obtaining your API Key: http://doc.livedns.gandi.net/#step-1-get-your-api-key 11 | # 12 | 13 | DOMAIN="example.net" 14 | RECORD="mywanip" 15 | APIKEY="my-api-key" 16 | 17 | 18 | API="https://dns.api.gandi.net/api/v5/" 19 | IP_SERVICE="http://me.gandi.net" 20 | 21 | IP4=$(curl -s4 $IP_SERVICE) 22 | IP6=$(curl -s6 $IP_SERVICE) 23 | 24 | if [[ -z "$IP4" && -z "$IP6" ]]; then 25 | echo "Something went wrong. Can not get your IP from $IP_SERVICE " 26 | exit 1 27 | fi 28 | 29 | 30 | if [[ ! -z "$IP4" ]]; then 31 | DATA='{"rrset_values": ["'$IP4'"]}' 32 | curl -s -XPUT -d "$DATA" \ 33 | -H"X-Api-Key: $APIKEY" \ 34 | -H"Content-Type: application/json" \ 35 | "$API/domains/$DOMAIN/records/$RECORD/A" 36 | fi 37 | 38 | if [[ ! -z "$IP6" ]]; then 39 | DATA='{"rrset_values": ["'$IP6'"]}' 40 | curl -s -XPUT -d "$DATA" \ 41 | -H"X-Api-Key: $APIKEY" \ 42 | -H"Content-Type: application/json" \ 43 | "$API/domains/$DOMAIN/records/$RECORD/AAAA" 44 | fi 45 | 46 | -------------------------------------------------------------------------------- /php/catalog/price-promo-by-tld.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | # 3 | # PHP example to list all extensions currently in promotion at Gandi 4 | # Requirements: PEAR XML_RPC2 package 5 | # Reference: http://doc.rpc.gandi.net/catalog/reference.html 6 | # 7 | # Limitations: 8 | # - Will not find promotion on second level top level domain names. 9 | # Do to so, query the Catalog API directly with a FQDN. 10 | # 11 | 'catalog.', 'sslverify' => False) 18 | ); 19 | 20 | // Parameters for catalog.list() 21 | $query_parms = array ( 22 | "product" => array ("type" => "domain"), 23 | "action" => array ("duration" => 1, 'name' => 'create') 24 | ); 25 | $currency = 'EUR'; 26 | $grid = 'A'; 27 | 28 | $result = $catalog_api->list($apikey, $query_parms, $currency, $grid); 29 | 30 | /* products which have a special catalog price have 'special_op' as 'true' 31 | as part of the additional unit_price array element in our result */ 32 | 33 | $promotions = array(); 34 | 35 | foreach($result as $res) { 36 | 37 | // Necessary loop as 'special_op' isn't always the first array element. 38 | $has_promotion = false; 39 | foreach($res['unit_price'] as $unit) { 40 | if ($unit['special_op'] == true) { 41 | $special_price = $unit['price']; 42 | $has_promotion = true; 43 | } 44 | 45 | else 46 | $regular_price = $unit['price']; 47 | } 48 | 49 | if ($has_promotion) { 50 | $promo_item = array( 'tld' => $res['product']['description'], 51 | 'special_price' => $special_price, 52 | 'regular_price' => $regular_price); 53 | array_push($promotions,$promo_item); 54 | } 55 | 56 | } 57 | 58 | // sort by domain name extension 59 | sort ($promotions); 60 | 61 | // print result 62 | echo "Current Gandi Promotions. Action: create (1 year), Grid: " . $grid . ", Currency: ". $currency . "\n"; 63 | printf ("Extension | Special Price | Regular Price\n"); 64 | printf ("----------------------------------------------------\n"); 65 | foreach ($promotions as $promo) { 66 | printf ("%-20s | %13.2f | %13.2f\n", $promo['tld'], $promo['special_price'], $promo['regular_price']); 67 | } 68 | ?> 69 | -------------------------------------------------------------------------------- /php/domain/price-list/DomainPrice.php: -------------------------------------------------------------------------------- 1 | doSearch("anydomainlabel"); // will search those extensions as defined in the class 17 | $results = $gapi->getCost(); // get the cost of the resulting available domains, returns cost & phase 18 | foreach ($results as $r) { 19 | echo $r['fqdn'] . "\t" . $r['available'] . " " . $r['cost'] . "\t" . $r['cost_vat'] . "\n"; 20 | } 21 | 22 | Note: 23 | - Currency and price grid may be set with the setCurrency, setGrid function. 24 | - To include the VAT (under your reseller account) in the cost calculation enable it in the class: 25 | $cost_vat_calculation = true; 26 | $currency_has_decimals = true; (if your currency has decimal points) 27 | - Update $search_extensions to include other extensions. 28 | 29 | */ 30 | 31 | require_once 'XML/RPC2/Client.php'; 32 | 33 | class DomainPrice 34 | { 35 | protected $api_key= ''; 36 | protected $domain_price_api; 37 | protected $search_time_seconds = 20; 38 | protected $search_extensions = array('.pizza','.tw','.taipei','.com','.com.tw','.blog','.online'); 39 | protected $search_results = array(); 40 | protected $domain_cost_list = array(); 41 | 42 | protected $grid = 'A'; 43 | protected $currency = 'USD'; 44 | protected $cost_vat_calculation = false; 45 | protected $currency_has_decimals = true; 46 | 47 | function getSearchResults() 48 | { 49 | return $this->search_results; 50 | } 51 | 52 | function getCost($includeUnavalable = false) 53 | { 54 | $this->domain_cost_list = array(); 55 | foreach ($this->search_results as $search_result) { 56 | if ($search_result["available"] === "available") { 57 | foreach ($search_result["prices"] as $price_item_prices) { 58 | $tax_rate = ($price_item_prices['taxes']['rate']); 59 | if ($search_result["current_phase"] === $price_item_prices["action"]["param"]["tld_phase"]) { 60 | foreach ($price_item_prices["unit_price"] as $unit_prices) { 61 | $price = $price_vat = $unit_prices['price']; 62 | if ($this->cost_vat_calculation == true) 63 | $price_vat += $price_vat * ($tax_rate/100); 64 | if ($this->currency_has_decimals == false) 65 | $price_vat = round($price_vat); 66 | 67 | $cost_element = array( 68 | 'fqdn' => $search_result["extension"], 69 | 'available' => $search_result["available"], 70 | 'phase' => $search_result["current_phase"], 71 | 'cost' => $price, 72 | 'cost_vat' => $this->cost_vat_calculation ? $price_vat : 0 73 | ); 74 | array_push($this->domain_cost_list,$cost_element); 75 | 76 | if ($unit_prices['special_op'] == true) 77 | break; 78 | } 79 | } 80 | } 81 | } 82 | else { 83 | if ($includeUnavalable) { 84 | $cost_element = array( 85 | 'fqdn' => $search_result["extension"], 86 | 'available' => $search_result["available"], 87 | 'phase' => $search_result["current_phase"], 88 | ); 89 | array_push($this->domain_cost_list,$cost_element); 90 | } 91 | } 92 | } 93 | return $this->domain_cost_list; 94 | } 95 | 96 | function setCurrency($currency) 97 | { 98 | $this->currency = $currency; 99 | } 100 | 101 | function setGrid($grid) 102 | { 103 | $this->grid = $grid; 104 | } 105 | 106 | function doSearch($search_label) 107 | { 108 | $fqdn_list = array(); 109 | 110 | foreach ($this->search_extensions as $extension) { 111 | array_push($fqdn_list,$search_label . $extension); 112 | } 113 | 114 | $search_results = array(); 115 | 116 | for ($i = 0;$i<$this->search_time_seconds;$i++) { 117 | 118 | $price_args = array( 119 | 'tlds' => $fqdn_list, 120 | 'grid' => $this->grid, 121 | 'currency' => $this->currency, 122 | 'action' => 'create', 123 | ); 124 | 125 | $price_listing = $this->domain_price_api->list( $this->api_key, $price_args); 126 | 127 | foreach ($price_listing as $price_item) { 128 | if ($price_item["available"] !== "pending") { 129 | array_push($this->search_results,$price_item); 130 | foreach (array_keys($fqdn_list, $price_item['extension'], true) as $key) { 131 | unset($fqdn_list[$key]); 132 | } 133 | } 134 | } 135 | 136 | if (sizeof($fqdn_list) == 0) 137 | break; 138 | 139 | sleep(1); 140 | } 141 | 142 | return true; 143 | } 144 | 145 | function __construct($api_key) 146 | { 147 | $this->api_key = $api_key; 148 | $this->domain_price_api = XML_RPC2_Client::create ( 149 | 'https://rpc.gandi.net/xmlrpc/', 150 | array('prefix' => 'domain.price.','sslverify' => False) 151 | ); 152 | } 153 | } 154 | 155 | ?> 156 | -------------------------------------------------------------------------------- /python/domain/contactsundermgnt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Simplified Python example to find contacts which are not created/managed by the reseller 4 | # Replace your-api-key with your API Key: https://wiki.gandi.net/en/xml-api 5 | 6 | import xmlrpclib 7 | 8 | api = xmlrpclib.ServerProxy('https://rpc.gandi.net/xmlrpc/') 9 | apikey = 'your-api-key' 10 | contacts = api.contact.list(apikey) 11 | domains = api.domain.list(apikey) 12 | for domain in domains: 13 | domaininfo = api.domain.info(apikey,domain['fqdn']) 14 | tech = str(domaininfo['contacts']['tech']['handle']) 15 | bill = str(domaininfo['contacts']['bill']['handle']) 16 | admin = str(domaininfo['contacts']['admin']['handle']) 17 | owner = str(domaininfo['contacts']['owner']['handle']) 18 | found_tech = False 19 | found_bill = False 20 | found_admin = False 21 | found_owner = False 22 | for contact in contacts: 23 | if (contact['handle'] == tech): 24 | found_tech = True 25 | if (contact['handle'] == bill): 26 | found_bill = True 27 | if (contact['handle'] == admin): 28 | found_admin = True 29 | if (contact['handle'] == owner): 30 | found_owner = True 31 | if (found_tech == False): 32 | print "Domain " + domain['fqdn'] + " Tech " + tech + " is not managed by us." 33 | if (found_bill == False): 34 | print "Domain " + domain['fqdn'] + " Bill " + bill + " is not managed by us." 35 | if (found_admin == False): 36 | print "Domain " + domain['fqdn'] + " Admin " + admin + " is not managed by us." 37 | if (found_owner == False): 38 | print "Domain " + domain['fqdn'] + " Owner " + owner + " is not managed by us." 39 | print "All contacts under our management:" 40 | for contact in contacts: 41 | print contact['handle'] 42 | -------------------------------------------------------------------------------- /python/domain/price/domain-price.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Output the creation price and phases of a specific domain name 4 | # (premium domain names included) 5 | # 6 | # Example: ./domain-pricy.py your-random-domain-name.net 7 | # Needs environment variable "GANDI_API_KEY" set with your Gandi API key 8 | # More details on this API: http://doc.rpc.gandi.net/domain/reference.html?#domain.price 9 | # 10 | import xmlrpclib 11 | import time 12 | import sys 13 | import os 14 | 15 | def handle_error( error_code): 16 | print 'invalid parameters or internal error. Details: ' + str(error_code) 17 | sys.exit() 18 | return 19 | 20 | try: 21 | gandi_apikey = os.environ["GANDI_API_KEY"] 22 | except KeyError: 23 | print "Please set the environment variable GANDI_API_KEY with your Gandi API key." 24 | sys.exit(1) 25 | 26 | if (len(sys.argv) > 1): 27 | domain = sys.argv[1] 28 | else: 29 | sys.exit(1) 30 | 31 | gandi_api = xmlrpclib.ServerProxy('https://rpc.gandi.net/xmlrpc/') 32 | 33 | try: 34 | r = gandi_api.domain.price(gandi_apikey, [domain]) 35 | except (xmlrpclib.Fault, \ 36 | xmlrpclib.ProtocolError, xmlrpclib.ResponseError), error_code: 37 | handle_error(error_code) 38 | if len(r) == 0: 39 | print "Invalid request." 40 | sys.exit(1) 41 | while (r[0]['available'] == 'pending'): 42 | time.sleep(0.7) 43 | try: 44 | r = gandi_api.domain.price(gandi_apikey, [domain]) 45 | except (xmlrpclib.Fault, \ 46 | xmlrpclib.ProtocolError, xmlrpclib.ResponseError), error_code: 47 | handle_error(error_code) 48 | if (r[0]['available'] == 'available'): 49 | for domains_avail in r[0]['prices']: 50 | r_phase = str(domains_avail['action']['param']['tld_phase']) 51 | for domain_prices in domains_avail['unit_price']: 52 | print domain + " Phase: " + r_phase + " Duration: " + \ 53 | str(domain_prices['min_duration']) + "-" + str(domain_prices['max_duration']) \ 54 | + "(" + str(domain_prices['duration_unit']) + ") " \ 55 | + str(domain_prices['price']) + " (" + domain_prices['currency'] \ 56 | + "/" + domain_prices['grid'] + ")" + " Price type: " \ 57 | + str(domain_prices['price_type']) 58 | for phases in r[0]['phases']: 59 | tldphase = str(phases['phase']) + " "; 60 | tldphase += "Start: " + str(phases['date_start']) + " " 61 | tldphase += "Start Gandi: " + str(phases['date_start_gandi']) + " "; 62 | tldphase += "End: " + str(phases['date_end']); 63 | print tldphase 64 | else: 65 | print domain + ': ' + (r[0]['available']) 66 | 67 | -------------------------------------------------------------------------------- /python/domain/price/simple-calls.py: -------------------------------------------------------------------------------- 1 | import xmlrpclib 2 | import pprint 3 | api = xmlrpclib.ServerProxy('https://rpc.gandi.net/xmlrpc/') 4 | apikey = 'YOURKEY' 5 | r = api.catalog.list(apikey, {'product':{'type': 'domain', 'description': '.at'}}) 6 | pprint.pprint(r) 7 | r = api.catalog.list(apikey, {'product':{'type': 'domain', 'description': '.asia'}},'TWD','C') 8 | pprint.pprint(r) 9 | r = api.catalog.list(apikey, {'product':{'type': 'domain', 'description': '.asia'},'action': {'name': 'create'}},'TWD','C') 10 | pprint.pprint(r) 11 | r = api.catalog.list(apikey, {'product':{'type': 'domain', 'description': '.asia'},'action': {'name': 'create','duration': 10}},'TWD','C') 12 | pprint.pprint(r) 13 | r = api.domain.price(apikey, ['gandi.sucks']) 14 | pprint.pprint(r) 15 | --------------------------------------------------------------------------------