Access to API is provided using
Before API can be used, the user has to register an Bulk Whois API account and obtain API credentials. When you are logged in Bulk Whois API , under My Account section, click API Credentials link in the left side menu.
All calls to Bulk Whois API are authenticated HTTPS POST requests, using application/x-www-form-urlencoded content type. All calls are made to URL in a generic format:
http://api.bulk-whois-api.com/api/$ACTION
Where $ACTION is specific to the request operation. Note that although our primary API endpoint does not run on HTTPS, it is still perfectly secure even if a third party can capture the network traffic between this endpoint and your application. The authentication protocol is designed not to send the API secret at any given time over the network, and it also mitigates other possible attacks. If you still need access via HTTPS, please contact support for an alternative API endpoint.
The authentication is implemented using three HTTP headers:
Key
- API Key.
Sign
- Lower case hex representation of HMAC SHA512 of the request.
Time
- Source server UTC date time specification in format YYYY-MM-DD hh:mm:ss. 24-hour format with leading zeros is required.
Time
is considered valid, if it is not off by more than 15 minutes compared to our server time.
Sign
is a hash calculated from a concatenation of Key
, Time
and request Body
using partner's API secret:
$SIGN := hmac_sha512($SECRET, $KEY + $TIME + $BODY).tolower()
See below section 5 for a working sample code.
Each API call can operate either in synchronous mode, asynchronous mode, polling mode, or any combination of these modes.
The default mode is synchronous mode and API calls that support synchronous mode do not need to specify extra parameters to use synchronous mode. In synchronous mode, the API server replies just after it obtains the requested data. This is usually fast and only take a couple of seconds, but in extreme cases, this can take up to 140 seconds, so setting a timeout to up to 150 seconds is a good idea. When you are using the synchronous mode, you can only do one query at the time. This is why we do not recommend using synchronous mode for large volume querying – use Asynchronous Mode instead, which supports performing multiple queries in parallel.
API calls that support asynchronous mode can be called with extra POST parameter asyncCallback
that
forces the call to run in asynchronous mode.
asyncCallback
(optional) - If present, it forces the API call to be processed in asynchronous
mode and it must be set to HTTP or HTTPS URL that is called by Bulk Whois API server once
the operation completes. The callback URL is called only in case the return value success
is 1
(see section 2.3) in the call API response.
The target script specified in the asyncCallback
argument receives a POST request with Content-Type
header set to application/json
.
The callback processing code must finish as soon as possible and send the response to the server callback request that contains a single text line:
BWA: OK
Callback targets that repeatedly do not respond with this line within 5 seconds can be blacklisted.
Many API calls support testMode
parameter for development purposes. If both testMode
and asyncCallback
arguments are set, validation is performed as in synchronous mode, but callback URL
is not called.
API calls that support polling mode can be called with extra POST parameter polling
that forces the call to
run in polling mode.
polling
(optional) - If set to 1, it forces the API call to be processed in polling mode. In this
mode, the API server replies immediately with a response, which informs the caller that the operation is in progress and provides a URL that the caller is expected to check periodically
to obtain the operation result. The result URL is provided in return value resultUrl
, and it is provided only if the value success
is 1 (see section 2.3) in the call API response. See section
2.3.1 below for more information.
Many API calls support testMode
parameter for development purposes. If both testMode
and polling
arguments are set, validation is performed as in synchronous mode, but no target result URL is provided and the operation is not executed.
The documentation of each API that supports polling mode contains information about the reasonable frequency of polling. Callers polling with much higher frequencies can be temporarily banned.
The caller can access the resultUrl
using both GET and POST methods, the authentication is not
required in this case.
A generic response to a Partner API request is in JSON format. In case of a successful call, the format is
{ "success":1, ... }
In case of an error, the format is
{ "success":0, "message":$MESSAGE }
where $MESSAGE
is a string.
In polling mode, the response format of a successful call is
{ "success":1, "resultUrl":"https://...", ... }
The resultUrl
is the URL that the caller is expected to poll to obtain the operation result. If the result is not
available when the caller checks, the value success
is 0 and the error message
is set to Pending.
All other values means that the task is completed (successfully or not) and the caller should not check
the resultUrl
anymore. Callers that keep polling after the task is complete can be blacklisted.
API calls can generate following general errors:
Value of returned $MESSAGE | Description |
---|---|
POST method is required. | The request used other than HTTP POST method. |
Authentication failed. Key header is missing. | The request did not contain HTTP header Key .
Authentication failed. |
Authentication failed. Sign header is missing. | The request did not contain HTTP header
Sign . |
Authentication failed. Time header is missing. | The request did not contain HTTP header
Time . |
Authentication failed. Invalid signature. | The signature was invalid. |
Authentication failed. Invalid time. Server time is YYYY-MM-DD hh:mm:ss. | The value of Time header was invalid. Either
the time was sent in an invalid format,
or the provided time differed for more than 15
minutes compared to our server's UTC time.
Our server's time in UTC is returned in the response.
|
No requests left. | API call was not executed because the calling account does not have any requests left. |
Blacklisted. | The caller does not conform to the API specification and used IP or URL was blacklisted. |
Slow down. | The caller executes too many requests too quickly. |
Pending. | The polling mode result URL informs the caller that the results are not available yet and it should keep polling. |
Invalid argument. ARG is invalid. | The value of ARG argument is invalid. The
argument's value was either in invalid format,
too long, or not unique as required. |
Invalid argument. ARG is missing. | The request did not contain ARG argument,
which was required. |
MODE mode is not supported. | Unsupported MODE mode was used with action that does not supported. |
Invalid request. | An error occurred during parsing the request. |
Unsupported. | Unsupported domain was queried. Currently, this is returned for .es and .my domains. |
Service error. | The request could not be completed due to error in the service. This could happen when a service is in a maintenance mode or due to an unexpected error. Please try again in a few minutes. If the problem persists for more than 30 minutes, please contact support. |
Supported modes: synchronous only
This action is implemented for the purpose of testing the authentication mechanism.
No additional values are returned.
Only general errors are returned.
Supported modes: synchronous only
Returns basic information about the account.
Following values are returned:
Name | Type | Description |
---|---|---|
string | Email address of the account owner. | |
requestsLeft | int | Number of allowed whois requests until next billing date or end of trial. |
Only general errors are returned.
Supported modes: synchronous + asynchronous + polling (5 seconds)
Gets WHOIS information for a domain or an IP address.
testMode
(optional) – If set to 1, a successful API call does not perform a WHOIS query. It just
validates the input and checks that the caller is able to perform the call (e.g. has enough requests).
Returned response may be incomplete.
query
– A second-level domain name for all top-level domains that allow Second-level domain
registration such as .com, .net, .info, .org, .eu, .de, etc. Or, a third-level domain for all other
top-level domains such as .uk, .br, .au, etc. Or, an IPv4 address. No subdomains, such as www,
are allowed.
Following values are returned:
Name | Type | Description |
---|---|---|
output | struct | WHOIS_OUTPUT structure, see below. |
rawOutput | array | Array of strings. Each string represents a complete response from WHOIS server. To get a final WHOIS record, 1-3 WHOIS requests are usually needed. This array contains responses to all requests |
WHOIS_OUTPUT
structure is defined as follows. However, there is no single standard for WHOIS records
format. Each WHOIS response is parsed and as many values as possible are extracted and provided in this
structure, but structures for different domains can contain and miss different values.
Name | Type | Description |
---|---|---|
domain | string | Name of the domain described by the record. |
domain_id | string | Unique domain ID used by some registrars. |
status | array | Array of strings that describe the status of the domain. Values can vary for different registrars. Common values are registered, available, CLIENT TRANSFER PROHIBITED, CLIENT DELETE PROHIBITED, CLIENT UPDATE PROHIBITED, clientDeleteProhibited, clientTransferProhibited, clientUpdateProhibited, redemptionPeriod. |
registered | bool | Set if the domain is registered. |
available | bool | Set if the domain is available. |
created_on | string | Date and time when the domain record was created. Typically in format YYYY-MM-DD hh:mm:ss TZ, where TZ is timezone information in format +XXXX or timezone abbreviation. |
updated_on | string | Date and time of the last update of the domain record. Typically in format YYYY-MM-DD hh:mm:ss TZ, where TZ is timezone information in format +XXXX or timezone abbreviation. |
expires_on | string | Date and time of the domain expiration. Typically in format YYYY-MM-DD hh:mm:ss TZ, where TZ is timezone information in format +XXXX or timezone abbreviation. registrar struct Information about domain registrar. Format is WHOIS_REGISTRAR structure, see below. |
registrar | struct | Information about domain registrar. Format is
WHOIS_REGISTRAR structure, see below. |
registrant_contact | struct | Information about entity that registered the domain. Format is WHOIS_CONTACT structure, see below. |
admin_contact | struct | Information about domain administrator. Format is WHOIS_CONTACT structure, see below. |
technical_contact | struct | Information about domain technical contact. Format is
WHOIS_CONTACT structure, see below. |
nameservers | array | Array of WHOIS_NAMESERVER structures, see below |
WHOIS_REGISTRAR
structure is defined as follows (again, not all values are always available):
Name | Type | Description |
---|---|---|
id | string | Identifier of the registrar. |
name | string | Name of the registrar. |
organization | string | Name of the registrar's organization. |
url | string | Web address of the registrar. |
WHOIS_CONTACT
structure is defined as follows (again, not all values are always available):
Name | Type | Description |
---|---|---|
id | string | Name of the domain described by the record. |
name | string | Unique domain ID used by some registrars. |
organization | string | Contact's organization. |
address | string | Contact's address. Usually a street or a full address including a city and a state. |
city | string | Contact's city. |
zip | string | Contact's ZIP code. |
state | string | Contact's state. |
country | string | Contact's country. |
country_code | string | Contact's country code. |
phone | string | Contact's phone number. |
fax | string | Contact's FAX number. |
string | Contact's email. | |
created_on | string | Date and time when the contact information was created. Typically in format YYYY-MM-DD hh:mm:ss TZ, where TZ is timezone information in format +XXXX or timezone abbreviation. |
updated_on | string | Date and time when the contact information was updated. Typically in format YYYY-MM-DD hh:mm:ss TZ, where TZ is timezone information in format +XXXX or timezone abbreviation. |
url | string | Web address of the contact. |
ref_url | string | Reference URL where it is possible to get additional information about the entity. |
handle | string | Contact's NIC handle. |
WHOIS_NAMESERVER
structure is defined as follows (again, not all values are always available):
Name | Type | Description |
---|---|---|
name | string | Host name of the name server. |
ipv4 | string | IPv4 address of the name server. |
ipv6 | string | IPv6 address of the name server. |
Only general errors are returned.
Bulk Whois API does have rate limits, which are currently set to 15 requests per 15 seconds. If a user attempts to perform more requests, "Slow down." error message will be returned (see section 2.3.2 above). If you need higher limits for your application, feel free to contact support. Most of the time we increase the limits free of charge per customer's needs.
A basic C# implementation that demonstrates how to call API in different modes. Please see section 2.2 for more information about the calling modes. Note that the synchronous mode should not be used for large volume querying.
Download sample View implementationusing System; using System.Text; using System.Threading; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Net; using System.Net.Sockets; using System.Net.Security; namespace BWA_API { class Program { static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: bwa-api <API Key> <API Secret>"); return; } // API initialization BwaApi api = new BwaApi(args[0], args[1]); // Test authentication BwaApiAuthTest authTest; if (api.AuthTest(out authTest)) { Console.WriteLine("Authentication test succeeded.\n"); } else Console.WriteLine("Authentication test failed: {0}", authTest.message); // Account information BwaApiInfo accountInfo; if (api.AccountInfo(out accountInfo)) { Console.WriteLine("Account info:"); Console.WriteLine(" Email: {0}", accountInfo.email); Console.WriteLine(" Requests left: {0}\n", accountInfo.requestsLeft); } else Console.WriteLine("Getting account information failed: {0}", accountInfo.message); // Synchronous Whois Query on domain string domain = "woot.com"; BwaApiWhoisQuery whoisQuerySync; if (api.WhoisQuerySynchronous(domain, out whoisQuerySync)) { Console.WriteLine("\nResult of synchronous whois query:"); PrintDomainResults(domain, whoisQuerySync); } else Console.WriteLine("Synchronous whois query failed: {0}", whoisQuerySync.message); BwaApiWhoisQuery whoisQueryPoll; if (api.WhoisQueryPolling(domain, out whoisQueryPoll)) { Console.WriteLine("\n\n\nResult of polling whois query:"); PrintDomainResults(domain, whoisQueryPoll); } else Console.WriteLine("Polling whois query failed: {0}", whoisQueryPoll.message); } static void PrintDomainResults(string Domain, BwaApiWhoisQuery WhoisQuery) { Console.WriteLine("Whois query ({0}):", Domain); Console.WriteLine(" Output:"); Console.WriteLine(" Domain: {0}", WhoisQuery.output.domain); Console.WriteLine(" Domain ID: {0}", WhoisQuery.output.domain_id); Console.WriteLine(" Status: {0}", WhoisQuery.output.status); Console.WriteLine(" Registered: {0}", WhoisQuery.output.registered); Console.WriteLine(" Available: {0}", WhoisQuery.output.available); Console.WriteLine(" Created on: {0}", WhoisQuery.output.created_on); Console.WriteLine(" Updated on: {0}", WhoisQuery.output.updated_on); Console.WriteLine(" Expires on: {0}", WhoisQuery.output.expires_on); if (WhoisQuery.output.registrar != null) { Console.WriteLine("\n Registrar:"); Console.WriteLine(" ID: {0}", WhoisQuery.output.registrar.id); Console.WriteLine(" Name: {0}", WhoisQuery.output.registrar.name); Console.WriteLine(" Organization: {0}", WhoisQuery.output.registrar.organization); Console.WriteLine(" URL: {0}", WhoisQuery.output.registrar.url); } if (WhoisQuery.output.registrant_contact != null) { Console.WriteLine("\n Registrant contact:"); Console.WriteLine(" ID: {0}", WhoisQuery.output.registrant_contact.id); Console.WriteLine(" Name: {0}", WhoisQuery.output.registrant_contact.name); Console.WriteLine(" Organization: {0}", WhoisQuery.output.registrant_contact.organization); Console.WriteLine(" Address: {0}", WhoisQuery.output.registrant_contact.address); Console.WriteLine(" City: {0}", WhoisQuery.output.registrant_contact.city); Console.WriteLine(" ZIP code: {0}", WhoisQuery.output.registrant_contact.zip); Console.WriteLine(" State: {0}", WhoisQuery.output.registrant_contact.state); Console.WriteLine(" Country: {0}", WhoisQuery.output.registrant_contact.country); Console.WriteLine(" Country code: {0}", WhoisQuery.output.registrant_contact.country_code); Console.WriteLine(" Phone: {0}", WhoisQuery.output.registrant_contact.phone); Console.WriteLine(" Fax: {0}", WhoisQuery.output.registrant_contact.fax); Console.WriteLine(" Email: {0}", WhoisQuery.output.registrant_contact.email); Console.WriteLine(" Url: {0}", WhoisQuery.output.registrant_contact.url); Console.WriteLine(" Created on: {0}", WhoisQuery.output.registrant_contact.created_on); Console.WriteLine(" Updated on: {0}", WhoisQuery.output.registrant_contact.updated_on); Console.WriteLine(" URL: {0}", WhoisQuery.output.registrant_contact.url); Console.WriteLine(" Ref URL: {0}", WhoisQuery.output.registrant_contact.ref_url); Console.WriteLine(" Handle: {0}", WhoisQuery.output.registrant_contact.handle); } if (WhoisQuery.output.admin_contact != null) { Console.WriteLine("\n Administrative contact:"); Console.WriteLine(" ID: {0}", WhoisQuery.output.admin_contact.id); Console.WriteLine(" Name: {0}", WhoisQuery.output.admin_contact.name); Console.WriteLine(" Organization: {0}", WhoisQuery.output.admin_contact.organization); Console.WriteLine(" Address: {0}", WhoisQuery.output.admin_contact.address); Console.WriteLine(" City: {0}", WhoisQuery.output.admin_contact.city); Console.WriteLine(" ZIP code: {0}", WhoisQuery.output.admin_contact.zip); Console.WriteLine(" State: {0}", WhoisQuery.output.admin_contact.state); Console.WriteLine(" Country code: {0}", WhoisQuery.output.admin_contact.country_code); Console.WriteLine(" Phone: {0}", WhoisQuery.output.admin_contact.phone); Console.WriteLine(" Fax: {0}", WhoisQuery.output.admin_contact.fax); Console.WriteLine(" Email: {0}", WhoisQuery.output.admin_contact.email); Console.WriteLine(" Url: {0}", WhoisQuery.output.admin_contact.url); Console.WriteLine(" Created on: {0}", WhoisQuery.output.admin_contact.created_on); Console.WriteLine(" Updated on: {0}", WhoisQuery.output.admin_contact.updated_on); Console.WriteLine(" URL: {0}", WhoisQuery.output.admin_contact.url); Console.WriteLine(" Ref URL: {0}", WhoisQuery.output.admin_contact.ref_url); Console.WriteLine(" Handle: {0}", WhoisQuery.output.admin_contact.handle); } if (WhoisQuery.output.technical_contact != null) { Console.WriteLine("\n Technical contact:"); Console.WriteLine(" ID: {0}", WhoisQuery.output.technical_contact.id); Console.WriteLine(" Name: {0}", WhoisQuery.output.technical_contact.name); Console.WriteLine(" Organization: {0}", WhoisQuery.output.technical_contact.organization); Console.WriteLine(" Address: {0}", WhoisQuery.output.technical_contact.address); Console.WriteLine(" City: {0}", WhoisQuery.output.technical_contact.city); Console.WriteLine(" ZIP code: {0}", WhoisQuery.output.technical_contact.zip); Console.WriteLine(" State: {0}", WhoisQuery.output.technical_contact.state); Console.WriteLine(" Country code: {0}", WhoisQuery.output.technical_contact.country_code); Console.WriteLine(" Phone: {0}", WhoisQuery.output.technical_contact.phone); Console.WriteLine(" Fax: {0}", WhoisQuery.output.technical_contact.fax); Console.WriteLine(" Email: {0}", WhoisQuery.output.technical_contact.email); Console.WriteLine(" Url: {0}", WhoisQuery.output.technical_contact.url); Console.WriteLine(" Created on: {0}", WhoisQuery.output.technical_contact.created_on); Console.WriteLine(" Updated on: {0}", WhoisQuery.output.technical_contact.updated_on); Console.WriteLine(" URL: {0}", WhoisQuery.output.technical_contact.url); Console.WriteLine(" Ref URL: {0}", WhoisQuery.output.technical_contact.ref_url); Console.WriteLine(" Handle: {0}", WhoisQuery.output.technical_contact.handle); } if (WhoisQuery.output.nameservers != null) { Console.WriteLine("\n Name servers:"); foreach (BwaApiWhoisNameServer ns in WhoisQuery.output.nameservers) { Console.WriteLine(" Server: {0}", ns.name); Console.WriteLine(" IPv4: {0}", ns.ipv4); Console.WriteLine(" IPv6: {0}", ns.ipv6); } } Console.WriteLine("\n\n Raw outputs:"); foreach (string ra in WhoisQuery.rawOutput) Console.WriteLine("-------------------------------------------------------------\n{0}\n", ra); } } }BwaApi.cs
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Security.Cryptography; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Web; using Newtonsoft.Json; namespace BWA_API { public class BwaApi { private string key; private string secret; private HMACSHA512 hashMaker; public const string ApiUrl = "http://api.bulk-whois-api.com/api/{0}"; public BwaApi(string Key, string Secret) { key = Key; secret = Secret; hashMaker = new HMACSHA512(Encoding.ASCII.GetBytes(secret)); } private static string ByteArrayToString(byte[] Bytes) { string hex = BitConverter.ToString(Bytes); return hex.Replace("-", ""); } private string Sign(string Message) { byte[] bytes = Encoding.UTF8.GetBytes(Message); byte[] hash = hashMaker.ComputeHash(bytes); return ByteArrayToString(hash).ToLower(); } private string SendRequest(string Action, NameValueCollection Params) { string responseData = null; try { string requestStr = string.Format(ApiUrl, Action); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestStr); request.Method = "POST"; string timeStr = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"); request.Headers["Key"] = key; request.Headers["Time"] = timeStr; string postData = ""; foreach (string pKey in Params) postData += string.Format("{0}{1}={2}", postData.Length > 0 ? "&" : "", HttpUtility.UrlEncode(pKey), HttpUtility.UrlEncode(Params[pKey])); string payloadToSign = string.Format(key + timeStr + postData); request.Headers["Sign"] = Sign(payloadToSign); byte[] postDataBytes = Encoding.UTF8.GetBytes(postData); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postDataBytes.Length; Stream dataStream = request.GetRequestStream(); dataStream.Write(postDataBytes, 0, postDataBytes.Length); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader respStream = new StreamReader(response.GetResponseStream()); responseData = respStream.ReadToEnd(); respStream.Close(); } catch { } return responseData; } private bool ProcessResponse<T>(string Json, ref T Response) where T : BwaApiResponse { bool result = false; if (!string.IsNullOrEmpty(Json)) { try { Response = JsonConvert.DeserializeObject<T>(Json); result = Response.success == 1; } catch { Response.message = "Invalid response received from API server."; } } else Response.message = "Unable to get response from API server."; return result; } public bool AuthTest(out BwaApiAuthTest Response) { Response = new BwaApiAuthTest(); string json = SendRequest("authTest", new NameValueCollection()); return ProcessResponse(json, ref Response); } public bool AccountInfo(out BwaApiInfo Response) { Response = new BwaApiInfo(); string json = SendRequest("info", new NameValueCollection()); return ProcessResponse(json, ref Response); } public bool WhoisQuerySynchronous(string Query, out BwaApiWhoisQuery Response) { Response = new BwaApiWhoisQuery(); NameValueCollection nvc = new NameValueCollection(); nvc.Add("query", Query); string json = SendRequest("query", nvc); return ProcessResponse(json, ref Response); } public bool WhoisQueryPolling(string Query, out BwaApiWhoisQuery Response) { bool result = false; Response = new BwaApiWhoisQuery(); BwaApiPollResponse pollingResponse = new BwaApiPollResponse(); NameValueCollection nvc = new NameValueCollection(); nvc.Add("query", Query); nvc.Add("polling", "1"); string json = SendRequest("query", nvc); if (ProcessResponse(json, ref pollingResponse)) { string url = pollingResponse.resultUrl; bool done = false; while (!done) { Thread.Sleep(5000); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader respStream = new StreamReader(response.GetResponseStream()); json = respStream.ReadToEnd(); respStream.Close(); result = ProcessResponse(json, ref Response); if (!result) { if (Response.message == "Pending.") { Response = new BwaApiWhoisQuery(); } else done = true; } else done = true; } catch { done = true; } } } else Response.message = pollingResponse.message; return result; } } public class BwaApiResponse { public int success; public string message; } public class BwaApiPollResponse : BwaApiResponse { public string resultUrl; } public class BwaApiAuthTest : BwaApiResponse { } public class BwaApiInfo : BwaApiResponse { public string email; public int requestsLeft; } public class BwaApiWhoisQuery : BwaApiResponse { public BwaApiWhoisOutput output; public string[] rawOutput; } public class BwaApiWhoisOutput { public string domain; public string domain_id; public string[] status; public bool registered; public bool available; public string created_on; public string updated_on; public string expires_on; public BwaApiWhoisRegistrar registrar; public BwaApiWhoisContact registrant_contact; public BwaApiWhoisContact admin_contact; public BwaApiWhoisContact technical_contact; public BwaApiWhoisNameServer[] nameservers; } public class BwaApiWhoisRegistrar { public string id; public string name; public string organization; public string url; } public class BwaApiWhoisContact { public string id; public string name; public string organization; public string address; public string city; public string zip; public string state; public string country; public string country_code; public string phone; public string fax; public string email; public string url; public string created_on; public string updated_on; public string url; public string ref_url; public string handle; } public class BwaApiWhoisNameServer { public string name; public string ipv4; public string ipv6; } }
A basic PHP 5 implementation that demonstrates how to call API in different modes. Please see section 2.2 for more information about the calling modes. Note that the synchronous mode should not be used for large volume querying.
Download sample View implementation<?php error_reporting(E_ALL); ini_set('display_errors', 1); include __DIR__ . "/BwaApi.php"; // Settings $apiKey = ""; $apiSecret = ""; // API initialization $api = new BwaApi($apiKey, $apiSecret); // Accept asynchronous callback. if ($_SERVER['REQUEST_METHOD'] === 'POST') { $json = file_get_contents('php://input'); if ($json) { echo "ODT: OK"; $response = json_decode($json, true); if ($response === null) { // error file_put_contents(__DIR__ . '/log.txt', var_export(array("error", $json, $response), true)); } else { // success file_put_contents(__DIR__ . '/log.txt', var_export(array("ok", $json, $response), true)); $whoisAsyncResult = new BwaApiWhoisQuery($response); $output = getDomainResults($whoisAsyncResult->output->domain, $whoisAsyncResult); file_put_contents(__DIR__ . '/result.txt', $output); } } exit; } // Test authentication $authTest = $api->authTest(); if ($authTest->success) { echo "Authentication test succeeded.\n"; } else { echo "Authentication test failed: " . $authTest->message; exit; } // Account information $accountInfo = $api->accountInfo(); if ($accountInfo->success) { echo "Account info:"; echo " Email: {$accountInfo->email}"; echo " Requests left: {$accountInfo->requestsLeft}\n"; } else { echo "Getting account information failed: " . $accountInfo->message; exit; } // Synchronous Whois Query on domain $domain = "woot.com"; $whoisQuerySync = $api->whoisQuerySynchronous($domain); if ($whoisQuerySync->success) { echo "\nResult of synchronous whois query:"; echo getDomainResults($domain, $whoisQuerySync); } else { echo "Synchronous whois query failed: " . $whoisQuerySync->message; exit; } // Asynchronous Whois Query on domain $domain = "woot.com"; $thisUrl = "http" . (!empty($_SERVER['HTTPS'])?"s":"") . "://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; $whoisQueryAsync = $api->whoisQueryAsynchronous($domain, $thisUrl); if ($whoisQueryAsync->success) { echo "\nResult of asynchronous whois query: Success"; } else { echo "Asynchronous whois query failed: " . $whoisQueryAsync->message; exit; } // Polling $whoisQueryPoll = $api->whoisQueryPolling($domain); if ($whoisQueryPoll) { echo "\n\n\nResult of polling whois query:"; echo getDomainResults($domain, $whoisQueryPoll); } else { echo "Polling whois query failed: " . $whoisQueryPoll->message; exit; } function getDomainResults($domain, BwaApiWhoisQuery $whoisQuery) { $output = "Whois query ({$domain}):"; $output .= "\n Output:"; $output .= "\n Domain: " . $whoisQuery->output->domain; $output .= "\n Domain ID: " . $whoisQuery->output->domain_id; $output .= "\n Status: " . implode(", ", $whoisQuery->output->status); $output .= "\n Registered: " . $whoisQuery->output->registered; $output .= "\n Available: " . $whoisQuery->output->available; $output .= "\n Created on: " . $whoisQuery->output->created_on; $output .= "\n Updated on: " . $whoisQuery->output->updated_on; $output .= "\n Expires on: " . $whoisQuery->output->expires_on; if ($whoisQuery->output->registrar != null) { $output .= "\n Registrar:"; $output .= "\n ID: " . $whoisQuery->output->registrar->id; $output .= "\n Name: " . $whoisQuery->output->registrar->name; $output .= "\n Organization: " . $whoisQuery->output->registrar->organization; $output .= "\n URL: " . $whoisQuery->output->registrar->url; } if ($whoisQuery->output->registrant_contact != null) { $output .= "\n Registrant contact:"; $output .= "\n ID: " . $whoisQuery->output->registrant_contact->id; $output .= "\n Name: " . $whoisQuery->output->registrant_contact->name; $output .= "\n Organization: " . $whoisQuery->output->registrant_contact->organization; $output .= "\n Address: " . $whoisQuery->output->registrant_contact->address; $output .= "\n City: " . $whoisQuery->output->registrant_contact->city; $output .= "\n ZIP code: " . $whoisQuery->output->registrant_contact->zip; $output .= "\n State: " . $whoisQuery->output->registrant_contact->state; $output .= "\n Country: " . $whoisQuery->output->registrant_contact->country; $output .= "\n Country code: " . $whoisQuery->output->registrant_contact->country_code; $output .= "\n Phone: " . $whoisQuery->output->registrant_contact->phone; $output .= "\n Fax: " . $whoisQuery->output->registrant_contact->fax; $output .= "\n Email: " . $whoisQuery->output->registrant_contact->email; $output .= "\n Created on: " . $whoisQuery->output->registrant_contact->created_on; $output .= "\n Updated on: " . $whoisQuery->output->registrant_contact->updated_on; $output .= "\n URL: " . $whoisQuery->output->registrant_contact->url; $output .= "\n Ref URL: " . $whoisQuery->output->registrant_contact->ref_url; $output .= "\n Handle: " . $whoisQuery->output->registrant_contact->handle; } if ($whoisQuery->output->admin_contact != null) { $output .= "\n Administrative contact:"; $output .= "\n ID: " . $whoisQuery->output->admin_contact->id; $output .= "\n Name: " . $whoisQuery->output->admin_contact->name; $output .= "\n Organization: " . $whoisQuery->output->admin_contact->organization; $output .= "\n Address: " . $whoisQuery->output->admin_contact->address; $output .= "\n City: " . $whoisQuery->output->admin_contact->city; $output .= "\n ZIP code: " . $whoisQuery->output->admin_contact->zip; $output .= "\n State: " . $whoisQuery->output->admin_contact->state; $output .= "\n Country code: " . $whoisQuery->output->admin_contact->country_code; $output .= "\n Phone: " . $whoisQuery->output->admin_contact->phone; $output .= "\n Fax: " . $whoisQuery->output->admin_contact->fax; $output .= "\n Email: " . $whoisQuery->output->admin_contact->email; $output .= "\n Created on: " . $whoisQuery->output->admin_contact->created_on; $output .= "\n Updated on: " . $whoisQuery->output->admin_contact->updated_on; $output .= "\n URL: " . $whoisQuery->output->admin_contact->url; $output .= "\n Ref URL: " . $whoisQuery->output->admin_contact->ref_url; $output .= "\n Handle: " . $whoisQuery->output->admin_contact->handle; } if ($whoisQuery->output->technical_contact != null) { $output .= "\n Technical contact:"; $output .= "\n ID: " . $whoisQuery->output->technical_contact->id; $output .= "\n Name: " . $whoisQuery->output->technical_contact->name; $output .= "\n Organization: " . $whoisQuery->output->technical_contact->organization; $output .= "\n Address: " . $whoisQuery->output->technical_contact->address; $output .= "\n City: " . $whoisQuery->output->technical_contact->city; $output .= "\n ZIP code: " . $whoisQuery->output->technical_contact->zip; $output .= "\n State: " . $whoisQuery->output->technical_contact->state; $output .= "\n Country code: " . $whoisQuery->output->technical_contact->country_code; $output .= "\n Phone: " . $whoisQuery->output->technical_contact->phone; $output .= "\n Fax: " . $whoisQuery->output->technical_contact->fax; $output .= "\n Email: " . $whoisQuery->output->technical_contact->email; $output .= "\n Created on: " . $whoisQuery->output->technical_contact->created_on; $output .= "\n Updated on: " . $whoisQuery->output->technical_contact->updated_on; $output .= "\n URL: " . $whoisQuery->output->technical_contact->url; $output .= "\n Ref URL: " . $whoisQuery->output->technical_contact->ref_url; $output .= "\n Handle: " . $whoisQuery->output->technical_contact->handle; } if ($whoisQuery->output->nameservers) { $output .= "\n Name servers:"; foreach ($whoisQuery->output->nameservers as $ns) { /** @var BwaApiWhoisNameServer $ns */ $output .= "\n Server: " . $ns->name; $output .= "\n IPv4: " . $ns->ipv4; $output .= "\n IPv6: " . $ns->ipv6; } } $output .= "\n\n Raw outputs:\n"; foreach ($whoisQuery->rawOutput as $ra) { $output .= "-------------------------------------------------------------\n{$ra}\n"; } return $output; }BwaApi.php
<?php class BwaApi { const API_URL = "http://api.bulk-whois-api.com/api/"; private $key; private $secret; public function __construct($key, $secret) { $this->key = $key; $this->secret = $secret; } /** * @param $action * @param array $params * @return array * @throws Exception */ private function sendRequest($action, array $params = array()) { $result = null; $postFields = http_build_query($params); $dateTime = new \DateTime('now', new \DateTimeZone('UTC')); $time = $dateTime->format('Y-m-d H:i:s'); $message = $this->key . $time . $postFields; $signature = hash_hmac('sha512', $message, $this->secret); // generate extra headers $headers = array( 'Sign: ' . $signature, 'Time: ' . $time, 'Key: ' . $this->key ); $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_URL, self::API_URL . $action); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); $res = curl_exec($ch); if ($res === false) { throw new \Exception('Could not get a reply: ' . curl_error($ch)); } else { $result = json_decode($res, true); if ($result === null) { throw new \Exception('Invalid response received.'); } } return $result; } public function authTest() { $response = $this->sendRequest("authTest"); $result = new BwaApiAuthTest($response); return $result; } public function accountInfo() { $response = $this->sendRequest("info"); $result = new BwaApiInfo($response); return $result; } public function whoisQuerySynchronous($query) { $response = $this->sendRequest("query", array('query' => $query)); $result = new BwaApiWhoisQuery($response); return $result; } public function whoisQueryAsynchronous($query, $callbackUrl) { $response = $this->sendRequest("query", array('query' => $query, "asyncCallback" => $callbackUrl)); $result = new BwaApiResponse($response); return $result; } /** * @param string $query * @return bool|BwaApiWhoisQuery false on error * @throws Exception */ public function whoisQueryPolling($query) { $result = false; $response = $this->sendRequest("query", array('query' => $query, 'polling' => "1")); $pollingResponse = new BwaApiPollResponse($response); // may throw exception $url = $pollingResponse->resultUrl; $done = false; while (!$done) { sleep(5); $json = file_get_contents($url); $response = json_decode($json, true); if ($response === null) { throw new \Exception("Invalid JSON."); } else { $result = new BwaApiWhoisQuery($response); if (!$result->success && $result->message === "Pending.") { # Not finished yet. } else { $done = true; } } } return $result; } } class BwaApiResponse { /** @var int */ public $success; /** @var string|null */ public $message; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiPollResponse extends BwaApiResponse { /** @var string */ public $resultUrl; } class BwaApiAuthTest extends BwaApiResponse { } class BwaApiInfo extends BwaApiResponse { /** @var string */ public $email; /** @var int */ public $requestsLeft; } class BwaApiWhoisQuery extends BwaApiResponse { /** @var BwaApiWhoisOutput */ public $output; /** @var string[] */ public $rawOutput; public function __construct(array $data) { parent::__construct($data); $output = array_key_exists('output', $data) ? $data['output'] : array(); $this->output = new BwaApiWhoisOutput($output); } } class BwaApiWhoisOutput { /** @var string */ public $domain; /** @var string */ public $domain_id; /** @var string[] */ public $status; /** @var bool */ public $registered; /** @var bool */ public $available; /** @var string */ public $created_on; /** @var string */ public $updated_on; /** @var string */ public $expires_on; /** @var BwaApiWhoisRegistrar|null */ public $registrar; /** @var BwaApiWhoisContact|null */ public $registrant_contact; /** @var BwaApiWhoisContact|null */ public $admin_contact; /** @var BwaApiWhoisContact|null */ public $technical_contact; /** @var BwaApiWhoisNameServer[] */ public $nameservers = array(); public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } if (!empty($data['registrar'])) { $this->registrar = new BwaApiWhoisRegistrar($data['registrar']); } foreach (array('registrant_contact', 'admin_contact', 'technical_contact') as $contactType) { if (!empty($data[$contactType])) { $this->{$contactType} = new BwaApiWhoisContact($data[$contactType]); } } if (!empty($data['nameservers'])) { $this->nameservers = array(); foreach ($data['nameservers'] as $nameserver) { $this->nameservers[] = new BwaApiWhoisNameServer($nameserver); } } } } class BwaApiWhoisRegistrar { /** @var string */ public $id; /** @var string */ public $name; /** @var string */ public $organization; /** @var string */ public $url; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiWhoisContact { /** @var string */ public $id; /** @var string */ public $name; /** @var string */ public $organization; /** @var string */ public $address; /** @var string */ public $city; /** @var string */ public $zip; /** @var string */ public $state; /** @var string */ public $country; /** @var string */ public $country_code; /** @var string */ public $phone; /** @var string */ public $fax; /** @var string */ public $email; /** @var string */ public $created_on; /** @var string */ public $updated_on; /** @var string */ public $url; /** @var string */ public $ref_url; /** @var string */ public $handle; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiWhoisNameServer { /** @var string|null */ public $name; /** @var string|null */ public $ipv4; /** @var string|null */ public $ipv6; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } }
This example demonstrates how to perform a large volume querying using Bulk Whois API. See the description in the sample source code for more information about this sample and instructions on how to use it.
Download sample View implementation<?php // // This script is an example of how to use Bulk Whois API in PHP 5. // It allows you to perform any amount of WHOIS queries written into an input file. // // This script is provided "AS IS" without warranties of any kind, either express or implied. // Everyone is allowed to use it, copy it, or create derived products from it, completely // free of charge, provided that Bulk Whois API TOS (see the link below) is respected // and not violated. // // // Copyright (c) 2015 - Bulk Whois API // // Relevant links: // * https://bulk-whois-api.com/ - Bulk Whois API homepage // * https://bulk-whois-api.com/documentation/ - Bulk Whois API documentation // * https://bulk-whois-api.com/privacy-policy-and-tos/ - Bulk Whois API TOS // // // How does it work? // * This script loads input queries stored in $whoisInputFile, separated by newlines. // * Each time it runs it removes the first line from the input file and sends it // as a query to BWA API server. // * Asynchronous callback mode is used with BWA API so that this script is called by BWA // API server when the job is done. // * BWA uses POST request with JSON data to report the results to the callback. // * The results from the server are written to $whoisResultsFile. Each result is written // on a separate line in the format "QUERY::RESULT" (without the quotes). // * The script logs its progress to $logFile, so in case of any problems, check the log // file. // // How to use it? // * You have to have BWA account with non-zero requests and obtain API key and secret. // See BWA API documentation on how to obtain API key and secret. // * Fill in your BWA API key and secret to $apiKey and $apiSecret global variables. // * Create a list of WHOIS queries and store them to whois-input.txt. // Separate queries in the input file with newlines. Each query should be either a domain // or IP address. // * Copy whois-input.txt, this script and BwaApi.php file to the same folder on a PHP // hosting server. // * Execute the script using your browser - simply access the script's URL. // * Wait until the input file is empty or until log file does not grow. // * If whois-input.txt is empty, the work is done. Otherwise, check bwa-log.txt to see // the problem. // include __DIR__ . "/BwaApi.php"; # Settings // Your API key & API secret $apiKey = 'Your API key here'; // BWA-XXX $apiSecret = 'Your API secret here'; // Is logging enabled $loggingEnabled = true; // Name of input file, in which queries waiting for processing are separated by newlines. $whoisInputFile = __DIR__ . '/whois-input.txt'; // Name of output file with unparsed results. $whoisResultsFile = __DIR__ . '/whois-results.txt'; // Name of log file. $logFile = __DIR__ . '/bwa-log.txt'; // URL of this script. $thisUrl = "http" . (!empty($_SERVER['HTTPS'])?"s":"") . "://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; ini_set('display_errors', 1); error_reporting(E_ALL); // API initialization $api = new BwaApi($apiKey, $apiSecret); // Setup unique token $token = uniqid(); if (isset($_GET["token"])) $token = $_GET["token"]; /** * Appends $message to file $fileName. * * @param string $fileName Name of the file to append to. * @param string $data Data to append. */ function fileAppend($fileName, $data) { $fp = fopen($fileName, "a"); flock($fp, LOCK_EX); fwrite($fp, $data); flock($fp, LOCK_UN); fclose($fp); } /** * Appends $message to log file with time stamp. * * @param string $message */ function mlog($message) { global $logFile, $loggingEnabled, $token; if ($loggingEnabled) { $dateTime = new \DateTime('now', new \DateTimeZone('UTC')); $time = $dateTime->format('Y-m-d H:i:s'); $line = '[' . $time . ']<' . $token . '> ' . $message . "\n"; fileAppend($logFile, $line); } } /** * Appends $message to output file. * * @param string $message */ function writeOutput($message) { global $whoisResultsFile; $line = $message . "\n"; fileAppend($whoisResultsFile, $line); } /** * This function is called during the initial request that starts the job. * It verifies that we have access rights to all files that we need. * * @return bool Returns true if succeeded, false otherwise. */ function initialization() { $result = false; global $whoisInputFile, $whoisResultsFile, $logFile; // Clean log file. $res = file_put_contents($logFile, ""); if ($res !== false) { mlog("initialization()"); // Check input is readable. $inputContents = file_get_contents($whoisInputFile); if ($inputContents !== false) { // Check input is writable. $res = file_put_contents($whoisInputFile, $inputContents); if ($res !== false) { // Clean output. $res = file_put_contents($whoisResultsFile, ""); if ($res !== false) { $result = true; } else mlog("initialization(): ERROR: Unable to write to output file " . "'$whoisResultsFile'."); } else mlog("initialization(): ERROR: Unable to write to input file '$whoisInputFile'."); } else mlog("initialization(): ERROR: Unable to read input file '$whoisInputFile'."); } else mlog("initialization(): ERROR: Unable to write to log file '$logFile'."); mlog("initialization(-):" . (int)$result); return $result; } /** * Checks if there are any incoming data in form of JSON POST. * If not, does nothing and returns immediately. If yes, the data are processed. * * @return bool Returns true if succeeded, false otherwise. */ function processIncomingData() { $result = false; if (!isset($_GET["query"])) $result = initialization(); mlog("processIncomingData()"); try { if (isset($_GET["query"])) { $query = $_GET["query"]; mlog("processIncomingData(): Query is '$query'.\n"); // Load data from input. $json = file_get_contents('php://input'); if ($json) { $jsonLen = strlen($json); mlog("processIncomingData(): Incoming data ($jsonLen bytes) detected " . "(first 256 bytes):\n" . substr($json, 0, 256) . "\n"); $response = json_decode($json, true); if ($response !== null) { $whoisAsyncResult = new BwaApiWhoisQuery($response); if ($whoisAsyncResult->success == 1) { mlog("processIncomingData(): Call succeeded."); } else { mlog("processIncomingData(): ERROR: Call failed with error message: '" . $response['message'] . "'"); } writeOutput($query . "::" . $json); $result = true; } else mlog("processIncomingData(): ERROR: Call failed. Server response is not a valid" . " JSON message."); } else mlog("processIncomingData(): ERROR: Call failed. No JSON POST data received."); } else mlog("processIncomingData(): No incoming data. Initialization called."); } catch (\Exception $e) { mlog("processIncomingData(): ERROR: Exception occurred: '" . $e->getMessage() . "'."); } mlog("processIncomingData(-):" . (int)$result); return $result; } /** * Removes and returns first line from the input file. * * @return string Returns first line of the input file if succeeded, false otherwise. */ function removeLineFromInputFile() { mlog("removeLineFromInputFile()"); global $whoisInputFile; $result = false; $lines = file($whoisInputFile, FILE_IGNORE_NEW_LINES); if ($lines !== false) { if (count($lines) > 0) { $firstLine = $lines[0]; $newLines = array_slice($lines, 1); $newContent = implode("\n", $newLines); $res = file_put_contents($whoisInputFile, $newContent); if ($res !== false) { $result = trim($firstLine); if (empty($result)) $result = false; } else mlog("removeLineFromInputFile(): ERROR: Unable to write to file" . " '$whoisInputFile'."); } else mlog("removeLineFromInputFile(): Empty input file '$whoisInputFile'."); } else mlog("removeLineFromInputFile(): ERROR: Unable to read from file" . " '$whoisInputFile'."); mlog("removeLineFromInputFile(-):" . ($result !== false ? $result : "false")); return $result; } // Return what is expected by API. echo "BWA: OK\n"; // If processing is OK, continue. if (processIncomingData()) { $done = false; while (!$done) { // Load query from input file. $query = removeLineFromInputFile(); if ($query !== false) { try { $arg = "query=" . urlencode($query) . "&token=" . urlencode($token); $url = strtok($thisUrl, '?') . "?$arg"; mlog("Callback URL set to '$url'."); $whoisQueryAsync = $api->whoisQueryAsynchronous($query, $url); if ($whoisQueryAsync->success) { mlog("API call succeeded, waiting for callback ..."); $done = true; } else { mlog("ERROR: API call failed with error: " . $whoisQueryAsync->message); writeOutput($query . "::" . json_encode($whoisQueryAsync)); } } catch (\Exception $e) { mlog("ERROR: Exception occurred: '" . $e->getMessage() . "'."); $done = true; } } else { mlog("No more queries to process, all done!"); $done = true; } } } else mlog("ERROR: Processing incoming data failed, stopping execution.");BwaApi.php
<?php class BwaApi { const API_URL = "http://api.bulk-whois-api.com/api/"; private $key; private $secret; public function __construct($key, $secret) { $this->key = $key; $this->secret = $secret; } /** * @param $action * @param array $params * @return array * @throws Exception */ private function sendRequest($action, array $params = array()) { $result = null; $postFields = http_build_query($params); $dateTime = new \DateTime('now', new \DateTimeZone('UTC')); $time = $dateTime->format('Y-m-d H:i:s'); $message = $this->key . $time . $postFields; $signature = hash_hmac('sha512', $message, $this->secret); // generate extra headers $headers = array( 'Sign: ' . $signature, 'Time: ' . $time, 'Key: ' . $this->key ); $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_URL, self::API_URL . $action); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); $res = curl_exec($ch); if ($res === false) { throw new \Exception('Could not get a reply: ' . curl_error($ch)); } else { $result = json_decode($res, true); if ($result === null) { throw new \Exception('Invalid response received.'); } } return $result; } public function authTest() { $response = $this->sendRequest("authTest"); $result = new BwaApiAuthTest($response); return $result; } public function accountInfo() { $response = $this->sendRequest("info"); $result = new BwaApiInfo($response); return $result; } public function whoisQuerySynchronous($query) { $response = $this->sendRequest("query", array('query' => $query)); $result = new BwaApiWhoisQuery($response); return $result; } public function whoisQueryAsynchronous($query, $callbackUrl) { $response = $this->sendRequest("query", array('query' => $query, "asyncCallback" => $callbackUrl)); $result = new BwaApiResponse($response); return $result; } /** * @param string $query * @return bool|BwaApiWhoisQuery false on error * @throws Exception */ public function whoisQueryPolling($query) { $result = false; $response = $this->sendRequest("query", array('query' => $query, 'polling' => "1")); $pollingResponse = new BwaApiPollResponse($response); // may throw exception $url = $pollingResponse->resultUrl; $done = false; while (!$done) { sleep(5); $json = file_get_contents($url); $response = json_decode($json, true); if ($response === null) { throw new \Exception("Invalid JSON."); } else { $result = new BwaApiWhoisQuery($response); if (!$result->success && $result->message === "Pending.") { # Not finished yet. } else { $done = true; } } } return $result; } } class BwaApiResponse { /** @var int */ public $success; /** @var string|null */ public $message; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiPollResponse extends BwaApiResponse { /** @var string */ public $resultUrl; } class BwaApiAuthTest extends BwaApiResponse { } class BwaApiInfo extends BwaApiResponse { /** @var string */ public $email; /** @var int */ public $requestsLeft; } class BwaApiWhoisQuery extends BwaApiResponse { /** @var BwaApiWhoisOutput */ public $output; /** @var string[] */ public $rawOutput; public function __construct(array $data) { parent::__construct($data); $output = array_key_exists('output', $data) ? $data['output'] : array(); $this->output = new BwaApiWhoisOutput($output); } } class BwaApiWhoisOutput { /** @var string */ public $domain; /** @var string */ public $domain_id; /** @var string[] */ public $status; /** @var bool */ public $registered; /** @var bool */ public $available; /** @var string */ public $created_on; /** @var string */ public $updated_on; /** @var string */ public $expires_on; /** @var BwaApiWhoisRegistrar|null */ public $registrar; /** @var BwaApiWhoisContact|null */ public $registrant_contact; /** @var BwaApiWhoisContact|null */ public $admin_contact; /** @var BwaApiWhoisContact|null */ public $technical_contact; /** @var BwaApiWhoisNameServer[] */ public $nameservers = array(); public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } if (!empty($data['registrar'])) { $this->registrar = new BwaApiWhoisRegistrar($data['registrar']); } foreach (array('registrant_contact', 'admin_contact', 'technical_contact') as $contactType) { if (!empty($data[$contactType])) { $this->{$contactType} = new BwaApiWhoisContact($data[$contactType]); } } if (!empty($data['nameservers'])) { $this->nameservers = array(); foreach ($data['nameservers'] as $nameserver) { $this->nameservers[] = new BwaApiWhoisNameServer($nameserver); } } } } class BwaApiWhoisRegistrar { /** @var string */ public $id; /** @var string */ public $name; /** @var string */ public $organization; /** @var string */ public $url; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiWhoisContact { /** @var string */ public $id; /** @var string */ public $name; /** @var string */ public $organization; /** @var string */ public $address; /** @var string */ public $city; /** @var string */ public $zip; /** @var string */ public $state; /** @var string */ public $country; /** @var string */ public $country_code; /** @var string */ public $phone; /** @var string */ public $fax; /** @var string */ public $email; /** @var string */ public $created_on; /** @var string */ public $updated_on; /** @var string */ public $url; /** @var string */ public $ref_url; /** @var string */ public $handle; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } } class BwaApiWhoisNameServer { /** @var string|null */ public $name; /** @var string|null */ public $ipv4; /** @var string|null */ public $ipv6; public function __construct(array $data) { foreach ($data as $key => $value) { if (!property_exists($this, $key)) { throw new \Exception("Invalid property {$key}."); } $this->{$key} = $value; } } }
A basic NodeJS implementation of a singe synchronous call of the query API. Note that the synchronous mode should not be used for large volume querying. The author of this sample is Francesco Merletti.
Download sample View implementation// This source code was kindly provided by Francesco Merletti. // To install dependencies run (note that a specific version of jssha is needed): // npm install request moment jssha@1.6.0 --save // Require necessary libs var request = require('request'), moment = require('moment'), jsSHA = require('jssha'), config = { bwaKey: 'YOUR BWA KEY HERE', bwaSecret: 'YOUR BWA SECRET HERE', bwaBaseUrl: 'http://api.bulk-whois-api.com/api/query' }; function getWhoisData(domain, callback) { 'use strict'; var date = moment.utc().format('YYYY-MM-DD HH:mm:ss'), requestBody = 'query=' + domain, shaObj = new jsSHA(config.bwaKey + date + requestBody, 'TEXT'), options = { url: config.bwaBaseUrl, method: 'POST', body: requestBody, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Key': config.bwaKey, 'Time': date, 'Sign': shaObj.getHMAC(config.bwaSecret, "TEXT", "SHA-512", "HEX").toLowerCase() } }; request(options, function (err, response, body) { if (err) { console.log('There was an error with the whois request.'); callback(err, null); return; } body = JSON.parse(body); if (response.statusCode !== 200 || body.success !== 1) { console.log('There was an error in the whois response.'); callback('Error', null); return; } // Get the data you need here or return the whole body.output callback(null, body.output); }); } getWhoisData('google.com', function (err, data) { if (err) { console.log(err); return; } console.log(data); })