API Usage


You are welcome to experiment with and incorporate this API in your application.

For premade scripts that probably integrate into your forum software, visit the members contributions page.

Code examples

You can find examples of code, to access the API, on the API code examples page. Currently, there is PHP but we hope that more people will provide code in as many languages as possible


This API is NOT to be used as a general software firewall. Checking every incoming connection against the API will be treated as a denial of service attack against us and will result in the immediate blocking of any offending IP addresses.

How to Use

It's just an HTTP GET or POST, and the page will return some simple XML indicating the type of search performed, whether it appears or not in our database, and the number of times it appears (frequency).

You can also POST to the API should you have privacy concerns that any listening/proxy service may record field data. The result data is unchanged

A typical successful response would look like this:

<response success="true">
    <lastseen>2007-09-18 05:48:53</lastseen>


The use of emailhash is a special example. You can pass the MD5 hash of an email address should you wish to not pass the email address itself. This method bypasses all blacklists, normalisation and obfuscation bypass checks.

Or via POST (PHP code example). If querying for multiple values for the same field (ie as below, multipls usernames) then POST data must be encoded using http_build_query()

// setup the URL
$url = 'http://api.stopforumspam.org/api';

$data = array(
    'username' => array(
    'email' => urlencode("xrumertest@this.baddomain.com"),
    'ip' => "",

$data = http_build_query($data);

// init the request, set some info, send it and finally close it
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);


return $result;

Multiple queries

Queries for some or all fields can be made in a single query, as here

Multi field queries will return data in the following default XML format

<response success="true">
    <lastseen>2009-10-26 11:55:07</lastseen>
    <lastseen>2009-06-25 00:24:29</lastseen>

NOTE: This is not standard or compliant XML and is depreciated. It is provided strictly for legacy purposes

Bulk queries

Up to 15 queries of any field combination can be made by constructing the fields as an array, as below

This query format is not compatible with the default XML format and because of this, the standard format this that query will return results as will XMLDOM

The default result will be formatted as below. Notice that the queried field is returned with the results so that matches can be made on the client. This is to remove any possible issues with results being reported out of order as submitted. If an email address has been altered for testing, such as when normalisation is required, then the normalized email is also returned in the results.

This format supports all XML and serialized response. Any fields over the 15 limit are disgarded. If the square brackets are excluded from any field, then that query will be ignored

Each bulk query of 5 field tests consumes one query and 0.2 for each field over 5

<?xml version="1.0" encoding="UTF-8"?>
    <lastseen>2011-01-10 00:31:06</lastseen>
    <lastseen>2011-02-07 22:27:08</lastseen>
    <lastseen>2010-08-08 16:59:06</lastseen>
    <lastseen>2011-02-10 23:51:37</lastseen>
    <lastseen>2011-02-17 13:02:31</lastseen>


Sometimes it is necessary to blacklist IP ranges, usernames and email domains.

When a query results in a blacklist result, the frequncy field will be a value of 255, and the lastseen date will update to the current time (UTC)

Serialised formatting

The default format is not XML compliant and is provided for legacy purposes only and will be depreciated and removed in further API versions. It is highly recommended that a serialised format is used. We provide several formats and are willing to add more if required

Strict XML results

Two XML formats are supported, XML DOM (Document Object Model) and CDATA (Character Data) encoded XML



<?xml version="1.0" encoding="UTF-8"?>
    <lastseen><![CDATA[2016-08-28 15:57:41]]></lastseen>

This call will return a mime type of text/xml



<?xml version="1.0" encoding="UTF-8"?>
    <lastseen>2016-08-28 15:56:47</lastseen>

Using these two XML formats will also set the correct HTTP headers to XML

This call will return a mime type of text/xml

PHP serialise

This would return the following result

a:2:{s:7:"success";i:1;s:5:"email";a:4:{s:8:"lastseen";s:19:"2016-08-28 16:04:45";s:9:"frequency";i:255;s:7:"appears";i:1;s:10:"confidence";d:99.950000000000003;}}

This call will return a mime type of text/txt


{"success":1,"email":{"lastseen":"2016-08-28 16:07:27","frequency":255,"appears":1,"confidence":99.95}}

This call will return a mime type of application/json

JSON Padding

We provide ajax/jquery support with JSONP, which allows for a callback function to be specified around a json result. If no callback function is provided then a standard json response will be provided.

myFunction({"success":1,"email":{"lastseen":"2016-08-28 16:08:09","frequency":255,"appears":1,"confidence":99.95}})

This call will return a mime type of text/javascript

Based on a return of "yes", you can choose to deny registration. The lookup is case insensitive, too. Note that you will get an error message if your IP address or email address is improperly formatted.

See the section below for a more reliable method of scoring queries.

IPv4 and IPv6 Support

The API supports both IPv4 and IPv6 queries and supports compressed and expanded IPv6 notation, and IPv4 mapped IPv6 addresses in ::FFFF: and ::ffff:0102:0304 formats

IPv6 formats supported

  • Full and compressed IPv6 [2e80:0:0:0:200:0:0:67cf and 2e80::200:0:0:67cf]
  • IPv4 mapped IPv6 - Hex and decimal [::ffff: and ::ffff:0a0b:0304]
  • IPv4 translatable IPv6 - Hex and decimal [64:ff9b::0102:0304 and 64:ff9b::]

HTTP and HTTPS Support

The API supports HTTP however the client must support SNI in order to validate certificate chains. If the client verifies the certificate chain by default, and SNI is not supported, then the connection will fail unless verify is disabled.

* The python included in Ubuntu 14.04 and below does not support SNI.

The API will accept connections on the following ports


  • Port 80


  • Port 443 (client must support SNI otherwise must have certificate verification disabled)

Geographic Access

The API provides several geographically diverse locations.

api.stopforumspam.org should be used as this will direct your query to the closest regional server in order to provide the quickest response. Should you wish to restrict traffic to a specific region, such as for compliance with company or country privacy regulations, then you can force a connection to a specific region.

To force a query to a server in the EU, make the query to europe.stopforumspam.org

To force a query to a server in the USA, make the query to us.stopforumspam.org

Confidence scoring

We include a statistically calculated score, based on the last seen date and the number of sightings. This score is included by default in all serialized/XML data but not in a standard/legacy API call. If you wish to see this score using a legacy API call, please include this in your URL parameter list


This confidence score is a reasonably good indicator that the field under test would result in unwanted activity. The figure is a floating point score, as a precentage. This score is included by default in all serialised formats



would respond with the result below, showing a confidence score on 31.64% likelihood of unwanted activity.

{"success":1,"username":{"lastseen":"2012-01-31 16:17:22","frequency":12,"appears":1,"confidence":31.64}}


We operate a list of email domaiNs, usernames and IP addresses that we consider hostile. You may wish to ignore these lists, in which case you need to add the following URL parameters

To ignore the email/domain list checks, add


To ignore the username (partial string) list checks, add


To ignore the IP lists (which includes some of the Internets most hostile spam friendly networks), add


Or to ignore all wildcard checks, append


Tor Exit Nodes

Whilst Tor is a fantasic tool, it is open to abuse. Some site administrators way wish to accept or discard traffic from Tor Exit nodes. We provide some options for this.

Known Tor exit nodes will be included in all serialised replies. If the IP address being queries is not a Tor exit node then this field will be obmitted from results.

{"success":1,"ip":{"torexit":1,"lastseen":"2016-06-22 17:36:47","frequency":30,"appears":1}}

Known Tor exit nodes will be included in all serialised replies. If you wish to ignore the listing for any known Tor exit node, then include the notorexit parameter in the request. Any IP address listed that is known as a Tor exit node will return a frequency of 0.


Some administrators may wish to block a known Tor exit node regardless of it's listing. A result for an IP that is recorded as a Tor exit node will return a frequency of 255 regardless of being listed or not. Whilst we do not recommend this action, we provide this data from publically available node lists. To return a "found" result in an IP address lookup for a known TOR exit node, use the badtorexit parameter

{"success":1,"ip":{"torexit":1,"lastseen":"2016-06-22 17:36:47","frequency":255,"appears":1}}


Email and usernames should be "url encoded". In PHP, this can be done using the urlencode() function

If your default character encoding is not ISO-8859-1 or UTF8, it is very important that you convert the username to UTF8 before urlencode. This should be performed for submissions and API lookups. A PHP example

$username = urlencode(iconv('GBK', 'UTF-8', $username));

Date/Time format

Appending &unix to any query will return data/time results as UNIXTIME format, that being seconds since Unix epoc

Error Reporting

Any errors reported, within the control of the API, will be presented in the format specified when querying the API, in the following structure (here as json)

{"success":0,"error":"request not understood"}

DNSBL Queries

Our data is now shared with dnsbl.tornevall.org, please consider incorporating DNS checks first to reduce load on our server. Check their usage page for instructions.

Adding to the Database

Submissions to the database first require an API key. You can then use our add form to submit your spammer data. Please note that if you sign up on our forums with the same email address you used when you registered your API key, your key will be pre-populated in the form as long as you're logged in.

You can automate submissions by making an HTTP GET to the following URLs. We support different methods for submissions

Standard form submission can be done with the following parameters:


Note: Username and Evidence fields must be converted to UTF-8 prior to submission. All fields must be urlencoded in order to preserve the correct details.

If required, data can be POSTed to the API, using the following example PHP code.

$ch = curl_init('https://www.stopforumspam.com/add');
if ($ch) {
  // if your curl version does not support SNI and you must use HTTPS then you may have to disable verify with 
  // curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
  curl_setopt ($ch, CURLOPT_POST, 1);
  curl_exec ($ch);
  curl_close ($ch);

The more reliable method is to use cURL, as above, but if cURL is not available then sockets can be used

function PostToHost($data) {
  $fp = fsockopen("www.stopforumspam.com",80);
  if ($fp) {
    fputs($fp, "POST /add.php HTTP/1.1\n" );
    fputs($fp, "Host: www.stopforumspam.com\n" );
    fputs($fp, "Content-type: application/x-www-form-urlencoded\n" );
    fputs($fp, "Content-length: ".strlen($data)."\n" );
    fputs($fp, "Connection: close\n\n" );
    fputs($fp, $data);
    // read the result
    $h = ''; while (!feof($fp)) { $h .= fgets($fp); } 

Other platforms will require different code. Some PHP servers do not support socket connections, so please investigate this before implementing a solution

To verify, check the HTTP status code returned. a 200 will indicate a successful submission, whereas a 403 will indicate an unsuccessful attempt. A reason will be given (inside a paragraph tag) for unsuccessful attempts. Nothing will be returned for a successful submission.

Note that all information is required to submit (username, email, and IP address) however the evidence field can remain empty.

API History

API version can be obtained by passing &version to the API.

Version 1.6 - October 2016

  • Added IPv6 support. IPv6 formats supported
    • Full and compressed IPv6 [ 2e80:0:0:0:200:0:0:67cf and 2e80::200:0:0:67cf ]
    • IPv4 mapped IPv6 - Hex and decimal [ ::ffff: and ::ffff:0a0b:0304 ]
    • IPv4 translatable IPv6 - Hex and decimal [ 64:ff9b::0102:0304 and 64:ff9b:: ]
    Please note - IPv6 Gateway suffix [eg %eth0] is not supported
  • Added ASN data for IP lookups*
  • Added delegated and country fields for IP lookups*
    • "country" is the country that the IP is registered as currently being allocated to.
    • "delegated" is the country that the IP was in at the time of the LAST addition to the database. This field is only returned when the IP field queried is listed.
  • Added support to POST to the API
  • Support IDN domain names in email address queries. These are converted to punycode and evaluated as ASCII
  • Email addresses with blacklisted IPs in their domain part will now respond as blacklisted.
  • Added ability to query email addresses using MD5 of email addresses (using the emailhash field). No email normalization on the server will be performed in this mode so this method will likely produce false negatives on checks with gmail addresses.
  • Added the &expire=age option. This provides the ability to have API results filtered if the lastseen date is older than the age (in days). If the lastseen date is 90 days ago and the &expire=60 parameter is passed with the query, then a "not found" API result will be returned.
  • Limited the API results for usernames to avoid excessive false positives. Usernames with a lastseen of over 90 days will not be reported in the API as found unless forced with the &expire parameter over 90.
  • Fixed json/jsonp results as 503 header wasnt being added when query rate had been exceeded.
  • Added PowerDNS response format for the http backend [more information to follow]

* Please note that country and ASN details are taken from publically available lists from each registrar. The country details are not taken from commerical GeoIP sources and will not be as accurate. If you require more accurate IP to country mapping then please consider IP2Location or MaxMind.  The default/legacy "XML" format will not return country data unless the &country is passed, and the ASN data will not return unless &asn is passed. This is to avoid breaking legacy parsing.


  • Your use of this data and supporting software is non-commercial.
  • No guarantees are made to any accuracy of any data provided to or by us. You use the data at your own risk. We cannot and will not be held responsible, in any form, for the data provided here or how it is used.
  • API queries are limited to 100,000 per day.
  • Hosting companies/providers have no permission to resell/package or charge access to the data here, or masquerade the data (or access to the data) as a provided service. The data here can be accessed by any commerical system provided that it is used for internal use only.
  • Any of the above terms may be waived, at the discretion, of the copyright holder (this website).
  • Anything else is covered under a Creative Commons License