Transit Service Programmatic Results API

The Programmatic Results application programming interface (API) allows direct retrieval of transit prediction results in machine-readable formats, suitable for scripting and automated workflows. It accepts the same query parameters as the web version of the Transit Service.

This service also supports file uploads of custom target lists, which is described in the Upload a Target List File section of this page.

There are also ready-to-use examples of single-target and dataset queries and on this page, as well as known errors and their causes.

Building an API Query

Step 1: Start with the API's base URL:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api

Step 2: Select an output format.

Use the &format= parameter to select the output format. The default is ipac.

Format valueDescription
ipacIPAC ASCII table format (default)
jsonJavaScript Object Notation object: {"stat":"OK","data":[...]}
csvComma-separated values with a header row
tsvTab-separated values with a header row

Step 3: Choose synchronous or asynchronous mode.

The API operates in two modes depending on the type of query:

Synchronous (single-target queries)
Requests using &sname= are executed synchronously. The result is returned directly in the HTTP response in the requested format.
Asynchronous (dataset queries)
Requests using any pre-defined dataset parameter (&extended=, &koi=, &k2=, &toi=) or file uploads (described below) are automatically executed asynchronously, because these searches can take several minutes to complete.

You can override this behavior with the &async= parameter:

ParameterEffect
&async=1Force asynchronous execution (also the default for dataset/upload queries).
&async=0Force synchronous execution even for dataset or upload queries. The result is returned directly in the HTTP response. Use with caution: Large searches may exceed the server timeout (120 s for synchronous queries) and return an error.

Async Response Workflow

When a search is run asynchronously, the server starts the search in the background and immediately sends back a brief acknowledgment rather than making you wait. This acknowledgment contains a poll URL—a web address you can check back on to find out whether the search has finished.

Think of it like a ticket number at a deli counter: you hand in your order, receive a ticket, and check the board periodically until your number comes up.

An async request immediately returns an HTTP 202 response with a "PENDING" status and a poll_url:

{"stat": "PENDING", "job_id": "<id>", "poll_url": "...?job_id=<id>&format=json"}

Check the poll_url periodically (e.g., every 10–30 seconds) until the status changes. Each time you visit the poll_url you will receive one of three status values:

Response statMeaning
"PENDING"Search is still running—poll again later.
"OK"Search completed—results are included in the response.
"ERROR"Search failed—see the "msg" field for details.

The poll_url honors the &format= parameter: append or change it at poll time to receive results in any supported format. You can also save the job_id from the initial response and construct the poll URL yourself later—job results are kept on the server for a reasonable period after the search completes.

Example Async Workflow

Step 3a: Submit (dataset queries are automatically async):

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?extended=conf_all&begin=2460000.0&end=2460007.0&format=json

Response (immediate):

{
  "stat": "PENDING",
  "job_id": "3f2a1b4c-...",
  "poll_url": "https://.../nph-transits-api?job_id=3f2a1b4c-...&format=json"
}

Step 3b: Poll the returned poll_url until "stat" is no longer "PENDING":

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?job_id=3f2a1b4c-...&format=json

Final response when complete:

{
  "stat": "OK",
  "data": [...]
}

Typical Response Times

Because dataset queries run asynchronously, the table below gives a rough guide to how long you should expect to wait before the poll URL returns "OK". Times were measured in May 2026 and will vary with server load. All figures are rounded up to the nearest 10 seconds.

Dataset Anywhere —
next transit
Anywhere —
custom week
Space obs (JWST) —
next transit
Ground obs —
next transit
All confirmed planets
(extended=conf_all)
~100 s~100 s~90 s~270 s
Confirmed transiting
(extended=conf_tran)
~90 s~110 s~90 s~240 s
Confirmed RV
(extended=conf_rv)
~30 s~30 s~30 s~100 s
All KOIs (conf + cand + FP)
(koi=koi_conf-koi_cand-koi_fp)
~50 s~60 s~50 s~70 s
All K2 (conf + cand + FP)
(k2=k2_conf-k2_cand-k2_fp)
~20 s~20 s~20 s~30 s
All TOIs
(toi=1)
~50 s~70 s~50 s~290 s

A few things to note:

  • Ground-based observatories trigger additional horizon, airmass, and twilight calculations for every candidate event, which is why those queries are significantly slower—especially for large datasets such as all TOIs or all confirmed planets.
  • Space observatories (e.g., JWST) skip the atmospheric/horizon calculations and are therefore comparable in speed to the no-site case.
  • Custom date-range queries ("custom week") can be slightly slower than next-transit queries because the service must enumerate all events within the window rather than stopping at the first one found.
  • Combining multiple datasets (e.g., extended=conf_all&koi=koi_conf&toi=1) will take longer than any single dataset—budget for the sum of the individual times as a conservative upper bound.
  • Poll your job every 15–30 seconds; polling more frequently will not speed up the result and adds unnecessary server load.

Synchronous timeout

If you force synchronous execution with &async=0, the server will abort and return an error after 120 seconds. Based on the table above, only small datasets (K2, confirmed RV) are reliably safe to run synchronously; most others risk hitting the timeout, particularly with a ground-based site.

Query Parameters

Step 4: Add Query Parameters

Target Selection

You can query a single target by name, or select from a pre-defined dataset, which is a ready-to-use collection of targets maintained by the Exoplanet Archive (for example, all confirmed transiting planets, or all TESS Objects of Interest). Pre-defined datasets save you from having to supply a target list yourself; the archive keeps them up-to-date as new planets are confirmed.

ParameterDescriptionExample
&sname=Single target by name&sname=HD+209458+b
Pre-defined archive datasets—use extended=, koi=, k2=, or toi=1 with dash-separated sub-selections:
&extended=conf_allAll confirmed planets&extended=conf_all
&extended=conf_tranConfirmed transiting planets&extended=conf_tran
&extended=conf_rvConfirmed RV planets&extended=conf_rv
&extended=conf_tran-conf_rvConfirmed transiting and RV planets&extended=conf_tran-conf_rv
&toi=1TESS Objects of Interest&toi=1
&koi=koi_confConfirmed Kepler Objects of Interest&koi=koi_conf
&koi=koi_candCandidate Kepler Objects of Interest&koi=koi_cand
&koi=koi_fpFalse-positive Kepler Objects of Interest&koi=koi_fp
&koi=koi_conf-koi_cand-koi_fpAll KOI sub-lists combined&koi=koi_conf-koi_cand-koi_fp
&k2=k2_confConfirmed K2 Objects of Interest&k2=k2_conf
&k2=k2_candCandidate K2 Objects of Interest&k2=k2_cand
&k2=k2_fpFalse-positive K2 Objects of Interest&k2=k2_fp
&k2=k2_conf-k2_cand-k2_fpAll K2 sub-lists combined&k2=k2_conf-k2_cand-k2_fp

Note: Multiple pre-defined datasets may be combined in a single request by including more than one dataset parameter, e.g., &extended=conf_all&koi=koi_conf&toi=1.


See also: Single-target examplesDataset examplesFile upload examples

Upload a Target List File

For custom target lists that are not part of a pre-defined archive dataset, you may upload a plain-text file containing target names and/or sky coordinates. File uploads use an HTTP POST multipart request to the same API base URL.

Accepted File Formats

Supported file extensions are .txt, .csv, and .tsv. The maximum number of targets per upload is 100, which will take around 15 minutes to return, due to the overhead incurred by individual target lookups.

Upload requests are always executed asynchronously—the immediate response will be a PENDING JSON with a poll_url to check back on.

Each non-blank, non-comment line is treated as one target. Comment lines begin with #. Three line formats are auto-detected:

FormatExample line
Target nameHD 209458 b
RA / Dec (decimal degrees)83.8221  -5.3911
Label + RA / DecMyTarget  83.8221  -5.3911

Fields may be separated by commas, tabs, or two or more spaces. Lines that cannot be parsed as RA/Dec are treated as target names.

Example file (my_targets.txt):

# Target name list
HD 209458 b
WASP-17 b

# RA/Dec pairs (decimal degrees)
83.8221  -5.3911

# Labeled RA/Dec
MyTarget  271.015  +44.500

Submitting an Upload Request

Send a POST multipart/form-data request with the file attached under the field name targetfile. All other API parameters (e.g., nextTransit=1, format=, site=, etc.) are passed as URL query parameters in the normal way.

curl example:

curl -F "targetfile=@my_targets.txt" \
  "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api\
?nextTransit=1&most_precise_ephem=1&format=json"

The immediate response is a PENDING JSON with a poll_url:

{
  "stat": "PENDING",
  "job_id": "3f2a1b4c-...",
  "poll_url": "https://.../nph-transits-api?job_id=3f2a1b4c-...&format=json"
}

Poll the poll_url periodically until the status is "OK" or "ERROR" (see Asynchronous Response Workflow, above). The final "OK" response contains a "data" array with one entry per transit event found. Targets that could not be resolved or searched are included as stub entries with an "error" field instead of transit data.

Python Examples

import requests
import time

API = "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api"

# ------------------------------------------------------------------
# Example 1: Single-target query (synchronous) — returns immediately
# ------------------------------------------------------------------
r = requests.get(API, params={
    "sname":              "HD 209458 b",
    "nextTransit":        "1",
    "most_precise_ephem": "1",
    "format":             "json",
})
result = r.json()
for row in result["data"]:
    print(row)

# ------------------------------------------------------------------
# Example 2: Single-target query, CSV format
# ------------------------------------------------------------------
r = requests.get(API, params={
    "sname":              "HD 209458 b",
    "nextTransit":        "1",
    "most_precise_ephem": "1",
    "format":             "csv",
})
print(r.text)   # CSV text with header row

# ------------------------------------------------------------------
# Example 3: Pre-defined dataset query (asynchronous — poll for results)
#
# Replace the dataset parameters to switch collections, e.g.:
#   Confirmed planets:         extended="conf_all"
#   Confirmed transiting only: extended="conf_tran"
#   TOIs:                      toi="1"
#   Confirmed KOIs:            koi="koi_conf"
#   Confirmed + candidate KOIs:koi="koi_conf-koi_cand"
#   K2 confirmed:              k2="k2_conf"
#   Multiple combined:         extended="conf_all", koi="koi_conf", toi="1"
#
# Replace format= with "csv", "tsv", or "ipac" as needed.
# ------------------------------------------------------------------
def poll_job(poll_url, interval=15):
    """Poll poll_url every `interval` seconds until the job is done."""
    while True:
        time.sleep(interval)
        r = requests.get(poll_url)
        state = r.json()
        print("Status:", state["stat"])
        if state["stat"] != "PENDING":
            return state

r = requests.get(API, params={
    "extended":    "conf_all",
    "nextTransit": "1",
    "format":      "json",
})
job = r.json()
print("Job submitted:", job["job_id"])
print("Poll URL:     ", job["poll_url"])

state = poll_job(job["poll_url"])

if state["stat"] == "OK":
    for row in state["data"]:
        print(row)
else:
    print("Error:", state.get("msg"))

# ------------------------------------------------------------------
# Example 4: Pre-defined dataset, CSV format (change format= at poll time)
# ------------------------------------------------------------------
r = requests.get(API, params={
    "toi":         "1",
    "nextTransit": "1",
    "format":      "csv",   # format is remembered in the poll_url
})
job = r.json()
state = poll_job(job["poll_url"])
if state["stat"] == "OK":
    print(state)   # for non-JSON formats the body is plain text, not a dict
                   # use requests.get(job["poll_url"]).text to retrieve it

# ------------------------------------------------------------------
# Example 5: Uploaded target list (asynchronous POST)
# ------------------------------------------------------------------
with open("my_targets.txt", "rb") as f:
    r = requests.post(
        API + "?nextTransit=1&most_precise_ephem=1&format=json",
        files={"targetfile": f},
    )
job = r.json()
print("Upload job:", job["job_id"])

state = poll_job(job["poll_url"])

if state["stat"] == "OK":
    for row in state["data"]:
        # Targets that failed to resolve have an "error" key instead of transit data
        if "error" in row:
            print("Failed:", row)
        else:
            print(row)
else:
    print("Error:", state.get("msg"))

Time Span Parameters

ParameterDescriptionExample
&nextTransit=1Next transit only (default)&nextTransit=1
&begin=Start of time range (JD)&begin=2460000.0
&end=End of time range (JD)&end=2460007.0

See also: Dataset examples (date-range queries)

Observer Location Parameters

Refer to the Transit Service Query Form for named observatories, for which you can use formats like
&site=kitt_peak or &site=Kitt Peak.
For custom lat/lon location, you can optionally set observatory name with &obsname=MyObservatory&lat=31.9&lon=-111.6.

ParameterDescriptionExample
&site=Named observatory&site=kitt_peak
&space_obs=Space observatory&space_obs=jwst
&lat= &lon=Custom latitude/longitude&lat=31.9&lon=-111.6

See also: Observer location examples

Orbital Phase Parameters

ParameterDescriptionExample
&phases=Comma-separated phase list&phases=0.0,0.5

See also: Orbital phase example

Ephemeris Selection Parameters

ParameterDescriptionExample
&most_precise_ephem=1Use the most precise available ephemeris&most_precise_ephem=1
&default_ephem=1Use the default archive ephemeris&default_ephem=1
&customParams=1Use custom ephemeris parameters (see below)&customParams=1

See also: Custom ephemeris example

Custom Ephemeris Parameters

When using &customParams=1, the following parameters override the archive ephemeris:

ParameterDescriptionExample
&period=Orbital period (days)&period=3.52474
&tranmid=Transit midpoint (JD)&tranmid=2452826.628
&tdur=Transit duration (hours)&tdur=3.1
&tranmiderr=Midpoint uncertainty (days)
&eccen=Eccentricity
&semim=Semimajor axis (au)
&srad=Stellar radius (solar radii)
&prad=Planet radius (Jupiter radii)

See also: Custom ephemeris example

Visibility Constraints Parameters

ParameterDescriptionExample
&vis_alt=Minimum target altitude (degrees)&vis_alt=30
&vis_air=Maximum airmass&vis_air=2.0
&twilight=Twilight angle (degrees, negative below horizon)&twilight=-12

See also: Observer location examples (include visibility constraints)

Example Requests

Single-Target Queries

Next transit, returned as default IPAC table format:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&most_precise_ephem=1

Next transit, returned as JSON:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&most_precise_ephem=1&format=json

Next transit, returned as CSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&most_precise_ephem=1&format=csv

Dataset Queries (asynchronous by default—poll the returned poll_url)

All confirmed planets over a date range, returned as IPAC table:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?extended=conf_all&begin=2460000.0&end=2460007.0&format=ipac

Confirmed transiting planets over a date range, returned as IPAC table:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?extended=conf_tran&begin=2460000.0&end=2460007.0&format=ipac

TESS Objects of Interest, next transit, returned as CSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?toi=1&nextTransit=1&format=csv

Confirmed and candidate KOIs, next transit, returned as TSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?koi=koi_conf-koi_cand&nextTransit=1&format=tsv

All K2 sub-lists combined, next transit, returned as default IPAC table format:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?k2=k2_conf-k2_cand-k2_fp&nextTransit=1

Force synchronous execution for a small dataset (returns immediately, but may time out for large searches), returned as CSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?toi=1&nextTransit=1&format=csv&async=0

Observer Location and Visibility

Single target observed from Kitt Peak with visibility constraints, returned as CSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&site=kitt_peak&vis_alt=30&twilight=-12&format=csv

Single target observed from a custom latitude/longitude, returned as TSV:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&lat=31.9&lon=-111.6&format=tsv

JWST observing windows for a single target, returned as JSON:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&space_obs=jwst&format=json

Custom Ephemeris

Single target with custom ephemeris parameters overriding the archive values, returned as JSON:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&customParams=1&period=3.52474&tranmid=2452826.628&tdur=3.1&format=json

Orbital Phase

Primary and secondary transits (phases 0.0 and 0.5) for a single target, returned as JSON:

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api?sname=HD+209458+b&nextTransit=1&phases=0.0,0.5&format=json

File Upload Queries (asynchronous POST—poll the returned poll_url)

Custom target list, next transit, returned as JSON:

curl -F "targetfile=@my_targets.txt" \
  "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api\
?nextTransit=1&most_precise_ephem=1&format=json"

Custom target list observed from Kitt Peak with visibility constraints, returned as CSV:

curl -F "targetfile=@my_targets.txt" \
  "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TransitSearch/nph-transits-api\
?nextTransit=1&site=kitt_peak&vis_alt=30&twilight=-12&format=csv"

Error Responses

Errors are always returned as JSON regardless of the requested format:

{"stat": "ERROR", "msg": "..."}

Common upload-specific errors:

MessageCause
Unsupported file type '.xyz'. Please upload one of: .txt, .csv, .tsv.Wrong file extension.
Uploaded file contains no valid targets.File was empty or contained only comments.
Uploaded file contains N targets; the maximum allowed is 500.File exceeds the per-request target limit.

«Previous Building a Transit Service Query by URL Viewing Predictions Next »



Last updated: 1 June 2026