GLOBAL AMATEUR RADIO ECOSYSTEM

Your Radio World.
One Platform.

A unified digital ecosystem for amateur-radio operators. Seamlessly integrate logging, awards tracking, and global DX intelligence into a single, high-performance interface.

GET STARTED
LOG IN

Install EQSL on your phone — opens like a real app from your home screen.

Global amateur radio network visualization

Built for the Modern Radio Operator

REAL-TIME SYNC

Instant cloud synchronization

CLOUD NATIVE

Access from anywhere

SECURE STORAGE

Encrypted operator data

CROSS-PLATFORM

Web, mobile, desktop

Everything Your Radio World, Connected

From your first QSO to your latest award — HAM-QS brings every part of your amateur radio journey together.

QSO
LOGBOOK
QSL
MAP
AWARDS
DX
CERTIFICATE

How It Works

01

Log

Record contacts in your digital logbook

02

Explore

Track DX entities and propagation

03

Achieve

Earn awards and certificates

04

Connect

Join the global radio community

LIVE DX INTELLIGENCE
UTC 14:45:22
TimeCallsignFrequencyStatus
14:21:059K2ABC14.074NEW ENTITY
14:20:42JA1XYZ7.074
14:19:18W1AW14.195
14:18:33VK9DX21.074NEW ENTITY

Connect Your Radio World.

GET STARTED
LOG IN

Install EQSL on your phone — opens like a real app from your home screen.

For developers

Complete API reference below: authentication, GET/POST/PATCH/DELETE, every endpoint, and a curl example for each method — use from your own website or app.

eQSL Public API

Use these methods from your own website or logging program. Every protected request needs your API key in the HTTP header. Parameters go in the URL path, the query string after ?, or the JSON body — each method below says exactly where.

Base URLhttps://www.eqsl.info/api/v1
Key locationHTTP header — never inside the URL
Header nameAuthorization: Bearer eqsl_live_YOUR_KEY
Methods31 endpoints documented below
Limit120 requests per minute per key

Where to put the API key

  1. Sign in at https://www.eqsl.info and open Dashboard → API Keys.
  2. Create a key and copy the full secret. It starts with eqsl_live_ and is shown once.
  3. On every request, add this header (replace the placeholder with your real key):
Authorization: Bearer eqsl_live_YOUR_KEY

Do not put the key in the URL, query string, or page source that visitors can see. Call the API from your server and keep the key in an environment variable. Required scope is listed on each method. Available scopes: profile:read, profile:write, qso:read, qso:write, qsl:read, qsl:write, awards:read, analytics:read, certificates:read, certificates:write, webhooks:read, webhooks:write.

JavaScript fetch example — the key is only in headers:

const res = await fetch("https://www.eqsl.info/api/v1/me", {
  headers: {
    "Authorization": "Bearer " + process.env.EQSL_API_KEY,
    "Accept": "application/json"
  }
});
const json = await res.json();
// Your details are in json.data
// If something failed, read json.error.code and json.error.message

Where parameters go

  • Path — part of the URL itself. Example: https://www.eqsl.info/api/v1/profiles/W1AW (callsign is W1AW).
  • Query — after a question mark, used to filter what you fetch. Example: https://www.eqsl.info/api/v1/qsos?band=20m&per_page=10
  • Body — JSON sent with POST or PATCH, with header Content-Type: application/json. This is where you write the details you want to save.

Successful JSON looks like:

{
  "data": { },
  "error": null,
  "meta": { "request_id": "req_...", "page": 1, "per_page": 50, "total": 1 }
}

Errors: 401 unauthorized (key missing or wrong), 403 forbidden (key missing that scope), 404 not found, 422 validation_error (bad parameter), 429 rate_limited.

Profiles

Read and update the operator account that owns the API key.

GET

Get your profile

scope profile:read

Returns the profile of the operator who owns this API key: callsign, display name, grid, country, and bio.

Details you receive: data.id, data.callsign, data.display_name, data.grid, data.country, data.bio, data.created_at

Complete URL

https://www.eqsl.info/api/v1/me

Pattern: https://www.eqsl.info/api/v1/me

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/me"
PATCH

Update your profile

scope profile:write

Changes fields on your own profile. Send only the fields you want to change. Callsign is stored in uppercase.

Details you receive: The updated profile (same fields as GET /me).

Complete URL

https://www.eqsl.info/api/v1/me

Pattern: https://www.eqsl.info/api/v1/me

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
callsignBodyNoASIM2Your station callsign.
display_nameBodyNoAsimName shown on the site.
gridBodyNoML64Maidenhead grid square.
countryBodyNoPakistanCountry name.
bioBodyNoHF operatorShort biography.

How to fetch it

curl -X PATCH -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"display_name":"Asim","grid":"ML64","country":"Pakistan"}' \
  "https://www.eqsl.info/api/v1/me"
GET

Look up a public profile

scope profile:read

Looks up another operator by callsign. Returns only public fields. Does not return email or private account data.

Details you receive: data.callsign, data.display_name, data.grid, data.country, data.bio

Complete URL

https://www.eqsl.info/api/v1/profiles/W1AW

Pattern: https://www.eqsl.info/api/v1/profiles/{callsign}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
callsignPathYesW1AWThe callsign to look up. Write it in the URL, not in the body.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/profiles/W1AW"

QSO logbook

Create, list, update, and delete contacts in the key owner's logbook.

GET

List your QSOs

scope qso:read

Returns your logged contacts, newest first. Use query parameters after ? to filter which contacts you receive. Pagination is in meta.page, meta.per_page, and meta.total.

Details you receive: Each QSO: id, callsign, qso_date, qso_time, freq, band, mode, rst_sent, rst_rcvd, grid, entity, notes, status, matched_qso_id

Complete URL

https://www.eqsl.info/api/v1/qsos?per_page=10&page=1&band=20m

Pattern: https://www.eqsl.info/api/v1/qsos?per_page=10&page=1&band=20m

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
pageQueryNo1Page number. Starts at 1.
per_pageQueryNo10How many QSOs to return (1–200). Default 50.
callsignQueryNoW1AWOnly QSOs with this callsign.
bandQueryNo20mOnly this band.
modeQueryNoFT8Only this mode.
statusQueryNoCONFIRMEDPENDING, CONFIRMED, or UNCONF.
sinceQueryNo2026-01-01QSOs on or after this date (YYYY-MM-DD).
untilQueryNo2026-12-31QSOs on or before this date.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/qsos?per_page=10&page=1&band=20m"
POST

Log a new QSO

scope qso:write

Adds one contact to your logbook. After save, the server tries to match it and refreshes awards. Status starts as PENDING.

Details you receive: The created QSO, including its id. Use that id for update, delete, or match.

Complete URL

https://www.eqsl.info/api/v1/qsos

Pattern: https://www.eqsl.info/api/v1/qsos

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
callsignBodyYesW1AWStation you worked.
qso_dateBodyYes2026-09-22Date in YYYY-MM-DD.
qso_timeBodyNo14:30UTC time. HH:MM or HH:MM:SS.
bandBodyNo20mBand, for example 40m, 20m, 2m.
modeBodyNoSSBMode, for example SSB, CW, FT8.
freqBodyNo14.074Frequency in MHz.
rst_sentBodyNo59Report you sent.
rst_rcvdBodyNo59Report you received.
gridBodyNoFN31Their grid square.
entityBodyNoUnited StatesDXCC entity or country.
notesBodyNoPOTAFree-text notes.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"callsign":"W1AW","qso_date":"2026-09-22","qso_time":"14:30","band":"20m","mode":"SSB"}' \
  "https://www.eqsl.info/api/v1/qsos"
GET

Get one QSO

scope qso:read

Returns a single contact that belongs to you. The id comes from the list or create response.

Details you receive: One QSO object (same fields as list).

Complete URL

https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001

Pattern: https://www.eqsl.info/api/v1/qsos/{id}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001QSO UUID. Replace {id} in the URL with this value.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001"
PATCH

Update a QSO

scope qso:write

Changes one or more fields on a contact you own. Send only the fields to change in the JSON body.

Details you receive: The updated QSO.

Complete URL

https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001

Pattern: https://www.eqsl.info/api/v1/qsos/{id}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001Which QSO to update.
notesBodyNoConfirmedAny QSO field from create may be sent.
bandBodyNo40mExample of a field you can change.

How to fetch it

curl -X PATCH -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"notes":"Updated from my website"}' \
  "https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001"
DELETE

Delete a QSO

scope qso:write

Removes one contact from your logbook and refreshes award progress. There is no request body.

Details you receive: data.id and data.deleted = true

Complete URL

https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001

Pattern: https://www.eqsl.info/api/v1/qsos/{id}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001Which QSO to delete.

How to fetch it

curl -X DELETE -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001"
POST

Upload many QSOs

scope qso:write

Creates up to 1000 contacts in one request. Invalid rows are skipped and listed in results. Valid rows are inserted.

Details you receive: data.inserted, data.failed, data.results (per row), data.qsos

Complete URL

https://www.eqsl.info/api/v1/qsos/bulk

Pattern: https://www.eqsl.info/api/v1/qsos/bulk

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
qsosBodyYes[{"callsign":"W1AW","qso_date":"2026-09-22"}]Array of QSO objects. Same fields as a single create.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"qsos":[{"callsign":"W1AW","qso_date":"2026-09-22","band":"20m","mode":"SSB"}]}' \
  "https://www.eqsl.info/api/v1/qsos/bulk"
POST

Match and confirm a QSO

scope qso:write

Tries to confirm this contact against the other station's log. A match needs the same callsign pair, same band, same mode, and times within 30 minutes. No JSON body is required.

Details you receive: data.matched, data.confirmed, data.newly_confirmed, data.qso

Complete URL

https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001/match

Pattern: https://www.eqsl.info/api/v1/qsos/{id}/match

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001The QSO to match.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/qsos/00000000-0000-0000-0000-000000000001/match"

ADIF import and export

Move a whole log in or out using ADIF text.

POST

Import an ADIF file

scope qso:write

Parses ADIF and inserts QSOs. Duplicates (same call, date, band, mode, and minute) are skipped unless you set mode=merge in the query string.

Details you receive: data.parsed, data.imported, data.skipped_duplicates, data.invalid

Complete URL

https://www.eqsl.info/api/v1/adif/import?mode=skip

Pattern: https://www.eqsl.info/api/v1/adif/import?mode=skip

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
modeQueryNoskipskip (default) ignores duplicates. merge inserts them anyway.
adifBodyYes<call:4>W1AW ...Raw ADIF text inside JSON: { "adif": "..." }. Or send the file as text/plain with no JSON wrapper.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"adif":"<ADIF_VER:5>3.1.4 <EOH>\n<CALL:4>W1AW <QSO_DATE:8>20260922 <BAND:3>20M <MODE:3>SSB <EOR>"}' \
  "https://www.eqsl.info/api/v1/adif/import?mode=skip"
GET

Download your log as ADIF

scope qso:read

Returns your log as an ADIF text file (not JSON). Optional query filters limit which QSOs are included.

Details you receive: A .adi file (Content-Type: text/plain).

Complete URL

https://www.eqsl.info/api/v1/adif/export?band=20m&since=2026-01-01

Pattern: https://www.eqsl.info/api/v1/adif/export?band=20m&since=2026-01-01

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
bandQueryNo20mExport only this band.
modeQueryNoFT8Export only this mode.
sinceQueryNo2026-01-01Start date.
untilQueryNo2026-12-31End date.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/adif/export?band=20m&since=2026-01-01"

eQSL cards

Send electronic QSL cards and read cards you sent or received.

GET

List eQSL cards

scope qsl:read

Lists cards. direction=sent shows cards you sent. direction=received shows cards addressed to you.

Details you receive: Each card: id, from_user_id, to_callsign, to_user_id, qso_id, message, status, created_at

Complete URL

https://www.eqsl.info/api/v1/qsl?direction=received&per_page=20

Pattern: https://www.eqsl.info/api/v1/qsl?direction=received&per_page=20

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
directionQueryNosentsent (default) or received.
statusQueryNoSENTPENDING, SENT, RECEIVED, or ARCHIVED.
pageQueryNo1Page number.
per_pageQueryNo20Cards per page.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/qsl?direction=received&per_page=20"
POST

Send an eQSL

scope qsl:write

Sends a card to a callsign. If that callsign has an account, they are linked automatically. Status is set to SENT.

Details you receive: The created card.

Complete URL

https://www.eqsl.info/api/v1/qsl

Pattern: https://www.eqsl.info/api/v1/qsl

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
to_callsignBodyYesW1AWWho receives the card.
qso_idBodyNo00000000-0000-0000-0000-000000000001Optional QSO this card confirms. Must be yours.
messageBodyNo73Short message on the card.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to_callsign":"W1AW","message":"Thanks for the QSO"}' \
  "https://www.eqsl.info/api/v1/qsl"
PATCH

Change eQSL status

scope qsl:write

Updates a card you sent or received. Setting status to RECEIVED notifies the sender (webhook qsl.received).

Details you receive: The updated card.

Complete URL

https://www.eqsl.info/api/v1/qsl/00000000-0000-0000-0000-000000000001

Pattern: https://www.eqsl.info/api/v1/qsl/{id}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001Card id from the list.
statusBodyYesRECEIVEDOne of PENDING, SENT, RECEIVED, ARCHIVED.

How to fetch it

curl -X PATCH -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"RECEIVED"}' \
  "https://www.eqsl.info/api/v1/qsl/00000000-0000-0000-0000-000000000001"

Analytics

Totals calculated from the key owner's logbook. No request body.

GET

Logbook summary

scope analytics:read

One overview of the whole log: how many QSOs, how many confirmed, unique callsigns, entities, bands, and modes, plus first and last QSO dates.

Details you receive: total_qsos, confirmed, pending, unconfirmed, unique_callsigns, unique_entities, unique_bands, unique_modes, first_qso, last_qso

Complete URL

https://www.eqsl.info/api/v1/analytics/summary

Pattern: https://www.eqsl.info/api/v1/analytics/summary

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/summary"
GET

DXCC / entities

scope analytics:read

Groups your QSOs by entity (country / DXCC name stored on each QSO).

Details you receive: total_entities and entities[] with key, count, confirmed

Complete URL

https://www.eqsl.info/api/v1/analytics/dxcc

Pattern: https://www.eqsl.info/api/v1/analytics/dxcc

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/dxcc"
GET

QSOs by band

scope analytics:read

Counts contacts per band.

Details you receive: bands[] with key, count, confirmed

Complete URL

https://www.eqsl.info/api/v1/analytics/bands

Pattern: https://www.eqsl.info/api/v1/analytics/bands

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/bands"
GET

QSOs by mode

scope analytics:read

Counts contacts per mode.

Details you receive: modes[] with key, count, confirmed

Complete URL

https://www.eqsl.info/api/v1/analytics/modes

Pattern: https://www.eqsl.info/api/v1/analytics/modes

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/modes"
GET

QSOs by country

scope analytics:read

Counts contacts per country/entity, same grouping as DXCC.

Details you receive: total_countries and countries[] with key, count, confirmed

Complete URL

https://www.eqsl.info/api/v1/analytics/countries

Pattern: https://www.eqsl.info/api/v1/analytics/countries

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/countries"
GET

Activity over time

scope analytics:read

Counts QSOs grouped by day, month, or year. Choose the grouping with the interval query parameter.

Details you receive: interval and trends[] with period, count, confirmed

Complete URL

https://www.eqsl.info/api/v1/analytics/trends?interval=month

Pattern: https://www.eqsl.info/api/v1/analytics/trends?interval=month

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
intervalQueryNomonthday, month (default), or year. This chooses how dates are grouped.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/analytics/trends?interval=month"

Awards

Award rules and your progress toward them.

GET

List award definitions

scope awards:read

Returns every award the platform offers (name, category, required count, rules). This is the catalog, not your personal progress.

Details you receive: Array of award definitions.

Complete URL

https://www.eqsl.info/api/v1/awards

Pattern: https://www.eqsl.info/api/v1/awards

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/awards"
GET

Your award progress

scope awards:read

Recalculates progress, then returns how far you are on each award and whether you are eligible (status COMPLETE).

Details you receive: earned, in_progress, and awards[] with progress, percent, status, eligible

Complete URL

https://www.eqsl.info/api/v1/awards/progress

Pattern: https://www.eqsl.info/api/v1/awards/progress

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/awards/progress"
POST

Recalculate awards

scope awards:read

Recomputes award progress from your log. If an award newly reaches COMPLETE, an award.earned webhook is sent. No JSON body is required.

Details you receive: refreshed: true and newly_earned award ids

Complete URL

https://www.eqsl.info/api/v1/awards/refresh

Pattern: https://www.eqsl.info/api/v1/awards/refresh

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/awards/refresh"

Certificates

Issue a certificate for a completed award, or check that a certificate is real.

GET

List your certificates

scope certificates:read

Returns certificates already issued to the key owner.

Details you receive: id, serial, verification_code, award_id, award_name, callsign, issued_at, revoked

Complete URL

https://www.eqsl.info/api/v1/certificates

Pattern: https://www.eqsl.info/api/v1/certificates

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/certificates"
POST

Issue a certificate

scope certificates:write

Creates a certificate only when that award status is COMPLETE for you. If one already exists and is not revoked, the existing certificate is returned.

Details you receive: serial, verification_code, award_name, callsign, issued_at

Complete URL

https://www.eqsl.info/api/v1/certificates

Pattern: https://www.eqsl.info/api/v1/certificates

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
award_idBodyYes00000000-0000-0000-0000-000000000001Award id from GET /awards or /awards/progress.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"award_id":"00000000-0000-0000-0000-000000000001"}' \
  "https://www.eqsl.info/api/v1/certificates"
GET

Verify a certificate

scope public

Public check. Anyone can call this without an API key. Put the verification code in the URL path.

Details you receive: valid, serial, award_name, callsign, issued_at — or valid false if missing or revoked

Complete URL

https://www.eqsl.info/api/v1/certificates/verify/AbCdEf123456

Pattern: https://www.eqsl.info/api/v1/certificates/verify/{code}

Where to write the key

No API key. This method is public. Do not send the Authorization header.

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
codePathYesAbCdEf123456verification_code from the certificate. Write it in the URL.

How to fetch it

curl "https://www.eqsl.info/api/v1/certificates/verify/AbCdEf123456"

Webhooks

Ask eQSL to POST an event to your website when something happens.

GET

List webhooks

scope webhooks:read

Returns webhook URLs registered on this account, including the signing secret.

Details you receive: id, url, secret, events, active, created_at

Complete URL

https://www.eqsl.info/api/v1/webhooks

Pattern: https://www.eqsl.info/api/v1/webhooks

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

No path, query, or body parameters. Call the complete URL with the key header.

How to fetch it

curl -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/webhooks"
POST

Create a webhook

scope webhooks:write

Subscribes an https URL to one or more events. eQSL generates a secret and signs each delivery with header X-Eqsl-Signature.

Details you receive: The webhook, including secret (store it to verify signatures).

Complete URL

https://www.eqsl.info/api/v1/webhooks

Pattern: https://www.eqsl.info/api/v1/webhooks

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
urlBodyYeshttps://your-site.com/eqsl-hookYour server URL that will receive POST requests.
eventsBodyYes["qso.confirmed"]One or more of: qsl.received, qso.confirmed, award.earned.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-site.com/eqsl-hook","events":["qso.confirmed","qsl.received","award.earned"]}' \
  "https://www.eqsl.info/api/v1/webhooks"
DELETE

Delete a webhook

scope webhooks:write

Stops deliveries to that URL. No request body.

Details you receive: data.id and data.deleted = true

Complete URL

https://www.eqsl.info/api/v1/webhooks/00000000-0000-0000-0000-000000000001

Pattern: https://www.eqsl.info/api/v1/webhooks/{id}

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001Webhook id from the list.

How to fetch it

curl -X DELETE -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/webhooks/00000000-0000-0000-0000-000000000001"
POST

Send a test event

scope webhooks:write

Posts a sample qso.confirmed payload to your webhook URL so you can confirm your server receives it. No JSON body.

Details you receive: delivered, status_code, error

Complete URL

https://www.eqsl.info/api/v1/webhooks/00000000-0000-0000-0000-000000000001/test

Pattern: https://www.eqsl.info/api/v1/webhooks/{id}/test

Where to write the key

HTTP header only: Authorization: Bearer eqsl_live_YOUR_KEY

Where to write each parameter

NameWrite it inRequiredExampleWhat it controls
idPathYes00000000-0000-0000-0000-000000000001Webhook to test.

How to fetch it

curl -X POST -H "Authorization: Bearer eqsl_live_YOUR_KEY" \
  "https://www.eqsl.info/api/v1/webhooks/00000000-0000-0000-0000-000000000001/test"

Call the API from another website

Put the key on your server. Your public webpage should call your own backend, and that backend calls eQSL.

// Your server (Node). Key stays in the environment, not in the browser.
const r = await fetch("https://www.eqsl.info/api/v1/qsos?per_page=10&band=20m", {
  headers: { Authorization: "Bearer " + process.env.EQSL_API_KEY }
});
const { data, error, meta } = await r.json();
# Python
import os, requests
r = requests.get(
    "https://www.eqsl.info/api/v1/analytics/summary",
    headers={"Authorization": "Bearer " + os.environ["EQSL_API_KEY"]},
)
print(r.json()["data"])

eQSL.info Public API · https://www.eqsl.info/api/v1 · 31 methods