Documentation

QSL World Developer API

Read your contacts, confirmations and statistics from your own scripts, logging tools and dashboards. A clean JSON API with ADIF export, for QSL World Pro members.

πŸ“’ Your log, as data

Every contact with band, mode, grid, park and summit references, and QSL status from LoTW, eQSL, QRZ and QSL World cards.

πŸ“€ ADIF export

One request gives a standards-compliant ADIF file, filtered by date, band, mode or station.

πŸ“Š Statistics

Totals, confirmations, DXCC entities, and counts by band and mode for your own award trackers.

πŸ”’ Private by design

A key reaches only its owner's logbook. Other stations' email and postal addresses are never part of the API.

Becoming a developer

The API is for registered developers. Anyone can read this documentation; to get API keys:

  1. Sign in to qslworld.com with an account that has an active QSL World Pro license (see plans).
  2. Open the developer dashboard, name your first app and accept the developer terms.
  3. In My apps, create an API key for the app. It is shown once: copy it into your program's settings.
  4. Try it in the API explorer, then watch your calls under Usage.

Keys work while the Pro license is active. If it lapses, requests answer 403 membership_required until it is renewed; the keys themselves are kept.

Quick start

Every request goes to https://qslworld.com/api/v1 with your key in the Authorization header.

curl -H "Authorization: Bearer qslw_YOUR_KEY" \
     "https://qslworld.com/api/v1/qsos?per_page=5"

The answer is JSON. Lists come back as data plus meta for paging:

{
  "data": [
    { "id": 912345, "call": "EA1AHP", "qso_date": "2026-10-01", "time_on": "18:42:15",
      "band": "20m", "freq": 14.076, "mode": "FT8", "rst_sent": "-12", "rst_rcvd": "-08",
      "gridsquare": "IN53", "country": "Spain", "dxcc": 281,
      "qsl": { "confirmed": true, "lotw_rcvd": true, ... }, ... }
  ],
  "meta": { "total": 7880, "page": 1, "per_page": 5, "pages": 1576, "has_more": true }
}

Authentication

Send the key as a bearer token in the Authorization header: Authorization: Bearer qslw_…. Keys are 45 characters and start with qslw_. Never put a key in the URL.

Keep keys secret. A key reads your whole logbook. Do not commit it to a public repository or put it in a web page anyone can view. If a key leaks, revoke it in the dashboard and create a new one. We store only a hash of each key, so a lost key cannot be shown again.

GET /ping needs no key and is handy for checking connectivity.

Rate limits

Each key may make 60 requests a minute and 5,000 a day (UTC). Every response carries the counters:

X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining-Minute: 57
X-RateLimit-Limit-Day: 5000
X-RateLimit-Remaining-Day: 4921

Over the limit the answer is 429 rate_limited with a Retry-After header in seconds. To read a whole logbook, prefer /export.adi or pages of 100 over many small requests.

Errors

Errors use HTTP status codes and a JSON body with a stable code you can test for:

{ "error": { "code": "invalid_key", "message": "That API key is not recognised." } }
StatuscodeMeaning
400bad_parameterA query parameter is malformed; the message says which.
401missing_key, invalid_key, revoked_keyNo key, an unknown key, or a revoked one.
403membership_requiredThe developer account has no active QSL World Pro license.
403developer_suspendedThe developer account was suspended; contact support.
404not_foundNo such endpoint, or no such contact in your logbook.
405method_not_allowedv1 is read-only: only GET.
409no_logbookYour account has no logbook yet.
429rate_limitedSlow down; see Retry-After.
500 / 503server_error, unavailableOur side. Retry later with back-off.

Endpoints

GET/ping

No key needed. Returns {"data":{"ok":true,"version":"1.0",…}}.

GET/me

The callsign the key belongs to, the key's name and scope, and your remaining limits.

GET/qsos

Your contacts, newest first, paged. All parameters are optional and combine:

ParameterExampleMeaning
page2Page number, from 1.
per_page100Rows per page, 1–100 (default 25).
orderascdesc (default, newest first) or asc.
from, to2026-01-01QSO date range, inclusive, UTC.
callEA1AHPExact callsign worked.
band20mExact band.
modeFT8Exact mode.
country, stateSpainExact country name or state.
gridsquareFNGrid prefix: FN matches FN42, FN31pr…
confirmedtruetrue or false: confirmed by LoTW, QRZ or a QSL World card.
logbook_id3Only one of your logbooks.
GET/qsos/{id}

One contact by its id.

GET/stats

Totals for your logbook: qsos, confirmed, countries, dxcc_entities, first_qso, last_qso, plus by_band and by_mode counts.

GET/export.adi

Your contacts as an ADIF 3.1.4 file, oldest first. Takes the same filters as /qsos. Up to 100,000 contacts per request; use from/to for more.

The contact object

Field names follow ADIF, in lower case. Empty fields are null. Dates are YYYY-MM-DD and times HH:MM:SS, both UTC; freq is in MHz.

FieldTypeNotes
idintegerStable id of the contact in QSL World.
callstringThe station worked.
qso_date, time_on, qso_date_off, time_offstringUTC.
band, band_rx, freq, freq_rxstring / numberBands like 20m; frequencies in MHz.
mode, submodestringADIF modes, e.g. FT8, MFSK/FT4.
rst_sent, rst_rcvdstring
name, qth, state, cnty, country, dxcc, cont, cqz, ituz, pfx, gridsquareThe other station, as logged. No email or street address.
tx_pwr, prop_mode, sat_name, sat_mode
iota, sota_ref, pota_ref, wwff_ref, sig, sig_infostringThe other station's references.
my_gridsquare, my_iota, my_sota_ref, my_pota_ref, my_wwff_ref, my_sig, my_sig_infostringYour references for the contact.
station_callsign, operatorstringThe callsign you used and who operated.
contest_id, stx, srx, stx_string, srx_stringContest exchange.
commentstring
qslobjectconfirmed (bool), lotw_sent, lotw_rcvd, lotw_date, eqsl_sent, eqsl_rcvd, qrz_rcvd, qrz_date, card_sent, card_rcvd.
logbook_idintegerWhich of your logbooks it is in.
created_atstringWhen it reached QSL World, ISO 8601.

Examples

Python: every contact, page by page

import requests

KEY = "qslw_YOUR_KEY"
url = "https://qslworld.com/api/v1/qsos"
page = 1
while True:
    r = requests.get(url, params={"page": page, "per_page": 100},
                     headers={"Authorization": f"Bearer {KEY}"}, timeout=30)
    r.raise_for_status()
    body = r.json()
    for q in body["data"]:
        print(q["qso_date"], q["time_on"], q["call"], q["band"], q["mode"])
    if not body["meta"]["has_more"]:
        break
    page += 1

JavaScript (Node 18+): confirmed contacts on 20 m this year

const KEY = process.env.QSLW_KEY;
const u = new URL("https://qslworld.com/api/v1/qsos");
u.search = new URLSearchParams({ band: "20m", confirmed: "true", from: "2026-01-01", per_page: "100" });
const r = await fetch(u, { headers: { Authorization: `Bearer ${KEY}` } });
const { data, meta } = await r.json();
console.log(`${meta.total} confirmed on 20m`, data.map(q => q.call));

curl: ADIF for September

curl -H "Authorization: Bearer qslw_YOUR_KEY" \
     -o september.adi \
     "https://qslworld.com/api/v1/export.adi?from=2026-09-01&to=2026-09-30"

Changelog

1.0 · October 2026 · First release: /ping, /me, /qsos, /qsos/{id}, /stats, /export.adi. Read-only. Writing contacts and ADIF import are planned for a later version.

Developer terms

Version 2026-10. These sit alongside the QSL World Terms of Use and Privacy Policy.

  1. The API is for registered developers with an active QSL World Pro license. Keys are personal to the developer account and reach only that account's logbook.
  2. Keep keys confidential. You are responsible for requests made with your keys. Revoke a key you believe has leaked.
  3. Respect the rate limits and do not try to get around them, for example with several keys for one program.
  4. Data from the API is your own log. If you build something other people use, ask for their own keys; do not collect other members' keys or data.
  5. Do not use the API to send unsolicited messages, to scrape QSL World, or for anything unlawful.
  6. The API may change. We announce breaking changes in this changelog ahead of time and keep /api/v1 working while it is current.
  7. We may suspend keys or developer accounts that break these terms or put the service at risk.
  8. The API is provided as is, without warranty. Questions: support@qslworld.com.