xMatch HTTP API

Documentation on the HTTP API for the CDS xMatch catalogue cross-matching service, with Python, Ruby and Java code examples.

Beside the xMatch web interface, the cross-match service can be accessed by scripts or programs through an API (Application Program Interface) described in this section. This API is partly compliant with concepts developed in the IVOA DALI document.

Base URL

The base URL for the API is :

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync.

Calls

Calls to the API can be performed using either GET or POST methods. However, if your request involves file uploads, you will be enforced to use the POST method.

Submitting a cross-match job

Compulsory parameters

ra,dec
267.22029,-20.35869
274.83971,-25.42714
275.92229,-30.36572
283.26621,-8.70756
306.01575,33.86756
322.493,12.16703

Total size of uploaded tables can not be larger than 100 MB.

If cat1 is an uploaded table or a pointer to a URL, the following parameters are also compulsory:

  • colRA1 - name of the column holding the right ascension. Example: colRA1=ra.
  • colDec1 - name of the column holding the declination. Example: colDec1=dec.

If cat2 is an uploaded table or a pointer to a URL, the following parameters are also compulsory:

  • colRA2 - name of the column holding the right ascension. Example: colRA2=ra.
  • colDec2 - name of the column holding the declination. Example: colDec2=dec.

Optional parameters

Have a look at the usage examples section for some practical cases.

Retrieving the available VizieR tables

To get the list of the VizieR tables which are available in the service, make a call to:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getVizieRTableNames&RESPONSEFORMAT=txt

You can also get back this list formatted as a JSON document:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getVizieRTableNames&RESPONSEFORMAT=json

Optionally you can ask for all tables (default) or only large, notlarge, medium or small tables using the option select. Example:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getVizieRTableNames&select=large&RESPONSEFORMAT=json

You can then retrieve more information about a specific table:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getInfo&tabName=TABLENAME

And the list of its columns:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getColList&tabName=TABLENAME&RESPONSEFORMAT=votable|json|csv|tsv|txt

You can also directly download the information of all tables with one call to:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables

Finally, you can also call:

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getPrettyNames

http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync/tables?action=getAliases

Successful queries

If the query was successful, the service will return a HTTP code 200. In addition, if the RESPONSEFORMAT was set to VOTable, the VOTable result document will contain, in the RESOURCE element and before the TABLE element, the following snippet: <INFO name="QUERY_STATUS" value="OK" />.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<VOTABLE ... >
    ....
    <RESOURCE type="results">
        <INFO name="QUERY_STATUS" value="OK" />
        <TABLE>
        ...
        </TABLE>
    </RESOURCE>
</VOTABLE>

Overflows

If the number of matching rows exceeds the value of the MAXREC parameter, the result will be truncated to MAXREC rows. If the RESPONSEFORMAT was set to VOTable, this truncation is indicated in the VOTable result document by the following snippet: <INFO name="QUERY_STATUS" value="OVERFLOW" />.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<VOTABLE ... >
    ....
    <RESOURCE type="results">
        <INFO name="QUERY_STATUS" value="OVERFLOW" />
        <TABLE>
        ...
        </TABLE>
    </RESOURCE>
</VOTABLE>

Error handling

If an error occurred during the processing of the cross-match job, the service will return one of the following HTTP codes:

In addition, a VOTable document is returned, including the following snippet:

<INFO name="QUERY_STATUS" value="ERROR">...</INFO>.

The text value of this INFO element provides with an explicit explanation of the origin of the problem.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<VOTABLE ... >
    ...
    <RESOURCE type="results">
        <INFO name="QUERY_STATUS" value="ERROR">
            Message: Missing parameter RESPONSEFORMAT.
            ...
        </INFO>
    </RESOURCE>
</VOTABLE>

API limitations

The following limitations apply:

Usage examples

curl

The curl command line below submits a list of position from the file posList.csv (positional columns being RAJ2000 and DEJ2000) and looks for counterparts in SIMBAD with a maximum search radius of 10 arcsec. The result is retrieved as a VOTable document.

curl -X POST -F request=xmatch -F distMaxArcsec=10 \
             -F RESPONSEFORMAT=votable \
             -F cat1=@posList.csv -F colRA1=RAJ2000 -F colDec1=DEJ2000 \
             -F cat2=simbad  http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync \
             > res.vot

wget

The following command line will perform the cross-match between VizieR catalogues V/123A/cv and V/106/lmxbcat with a maximum search radius of 22 arcsec and will retrieve the result as a CSV file.

wget -O xmatch-result.csv \
     "http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync?REQUEST=xmatch\
     &cat1=vizier:V/123A/cv&cat2=vizier:V/106/lmxbcat\
     &distMaxArcsec=22&RESPONSEFORMAT=csv"

Python

The Python script below consumes the API by submitting a list of positions from a VOTable file, looking for counterparts in the 2MASS catalogue (table II/246/out in VizieR). It requires the Requests library (that we recommend when dealing with HTTP in Python).

#!/usr/bin/env python
import requests

r = requests.post(
         'http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync',
         data={'request': 'xmatch', 'distMaxArcsec': 5, 'RESPONSEFORMAT': 'csv',
         'cat2': 'vizier:II/246/out', 'colRA1': 'RAJ2000', 'colDec1': 'DEJ2000'},
         files={'cat1': open('posList.vot', 'r')})

h = open('results.csv', 'w')
h.write(r.text)
h.close()

Ruby

This Ruby script submits a list of positions stored in the VOTable file postList.vot and looks for counterparts in SIMBAD. We limit the number of rows in the result (using the MAXREC parameter). The script requires the 'net/http/post/multipart' gem.

#!/usr/bin/ruby

require 'rubygems'
require 'net/http/post/multipart'

url = URI.parse('http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync')
File.open("./posList.vot") do |posList|
    req = Net::HTTP::Post::Multipart.new url.path,
        "request" => "xmatch",
        "cat1" => UploadIO.new(posList, 'application/x-votable+xml', 'posList.vot'),
        "cat2" => "simbad",
        "distMaxArcsec" => "9",
        "RESPONSEFORMAT" => "votable",
        "colRA1" => "RAJ2000",
        "colDec1" => "DEJ2000",
        "MAXREC" => "10"
    req.add_field("User-Agent", "Ruby")
    res = Net::HTTP.start(url.host, url.port) do |http|
        response = http.request(req)
        puts response.body
    end
end

Java

This example requires the HttpCore and HttpClient modules from the Apache HttpComponents project. It submits a list of positions extracted from the CSV file postList.csv and looks for counterparts in the Hipparcos catalogue (designated I/239/hip_main in VizieR) with a maximum search radius of 15 arcsec.

import java.io.*;

import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.entity.mime.*;
import org.apache.http.entity.mime.content.*;



public class SubmitJob {

  public static void main(String[] args) {
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost("http://cdsxmatch.cds.unistra.fr/xmatch/api/v1/sync");
    MultipartEntity entity = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE );

    try {
      entity.addPart( "request", new StringBody("xmatch"));
      entity.addPart( "distMaxArcsec", new StringBody("15"));
      entity.addPart( "RESPONSEFORMAT", new StringBody("csv"));
      entity.addPart( "colRA1", new StringBody("RAJ2000"));
      entity.addPart( "colDec1", new StringBody("DEJ2000"));

      entity.addPart( "cat1", new FileBody(new File("posList.csv")));
      entity.addPart( "cat2", new StringBody("vizier:I/239/hip_main"));

      httpPost.setEntity(entity);

      HttpResponse response = httpClient.execute(httpPost);

      BufferedInputStream in = new BufferedInputStream(
                                   response.getEntity().getContent());
      BufferedOutputStream out = new BufferedOutputStream(
                                   new FileOutputStream(new File("result.vot")));
      // copy result to file
      byte[] buffer = new byte[1024];
      int len = in.read(buffer);
      while (len != -1) {
        out.write(buffer, 0, len);
        len = in.read(buffer);
      }
      out.close();

    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
}