HamLink
HomeHow It WorksHamLink MailRadio NetworkGatewaysEmergencyVolunteerDownload BridgeDocumentationAboutContact
Download Bridge InternetLog InCreate Account
HamLink
HamLink

One mailbox. More than one way to reach it.

HamLinkAboutHow It WorksRadio NetworkGatewaysVolunteer NetworkEmergency Communications
ProductHamLink MailDownload BridgeSupported EquipmentSystem StatusDocumentation
HelpGetting StartedFAQTroubleshootingContact Us
LegalTerms of ServicePrivacy PolicyAcceptable UseRadio Communications PolicyCopyrightData & Account DeletionDisclaimer
HamLink • 2026Internet when available. Radio when needed.
HAMLINK API v1

How to use the HamLink API.

Register, create an API key, then call /api/v1 from another website or app. The examples below use curl. The same JSON works from JavaScript fetch and the HamLink SDK.

StartOther websitesProfileContactsMessagesStationLimitsAll routes

Start here

HamLink API v1 lives at /api/v1. Send JSON. Every answer uses the same shape, so another website can check ok before it reads data.

Success

{
  "ok": true,
  "data": { }
}

Failure

{
  "ok": false,
  "error": "Unauthorized.",
  "code": "unauthorized"
}

Sign in and open the API page to copy your key. It starts with hlk_. Send it on every private request:

Header

Authorization: Bearer hlk_your_key
Content-Type: application/json

Browsers on other websites may call this API directly. CORS allows GET, POST, PATCH, PUT, and DELETE. The official client is the HamLink SDK.

Show an operator on another website

This route needs no key. It returns the public card only: name, callsign, country, address, and volunteer status. It does not return email, messages, or device secrets.

Request

curl https://www.hamlink.info/api/v1/public/operators/K2ABC

Response

{
  "ok": true,
  "data": {
    "callsign": "K2ABC",
    "display_name": "Alex",
    "country": "Kuwait",
    "address": "k2abc@hamlink.radio",
    "volunteer": {
      "role": "gateway",
      "country": "Kuwait",
      "online": true
    }
  }
}

Browser example

const res = await fetch("https://www.hamlink.info/api/v1/public/operators/K2ABC");
const body = await res.json();
if (!body.ok) throw new Error(body.error);

const op = body.data;
document.getElementById("hamlink").textContent =
  op.display_name + " · " + op.callsign + " · " + (op.country || "Unknown");

Unknown callsigns return 404 with code: "not_found". You can also look up k2abc@hamlink.radio in the same path.

Update your profile and addresses

Same fields as Settings → Account. Send only the fields you want to change.

Update profile

curl -X PATCH https://www.hamlink.info/api/v1/me \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Alex",
    "country": "Kuwait",
    "callsign": "K2ABC"
  }'

Add an address

curl -X POST https://www.hamlink.info/api/v1/addresses \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "address": "club" }'

club becomes club@hamlink.radio. The primary address cannot be deleted. Remove an extra address with DELETE /api/v1/addresses/ADDRESS_ID.

Contacts

Create

curl -X POST https://www.hamlink.info/api/v1/contacts \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Relay Station",
    "address": "g0xyz@hamlink.radio",
    "callsign": "G0XYZ"
  }'

Response

{ "ok": true, "data": { "id": "CONTACT_ID" } }

Update

curl -X PATCH https://www.hamlink.info/api/v1/contacts/CONTACT_ID \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Updated name" }'

Delete

curl -X DELETE https://www.hamlink.info/api/v1/contacts/CONTACT_ID \
  -H "Authorization: Bearer hlk_your_key"

List them with GET /api/v1/contacts.

Messages

Send

curl -X POST https://www.hamlink.info/api/v1/messages \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "g0xyz@hamlink.radio",
    "subject": "Net tonight",
    "body": "I will be on the gateway at 19:00.",
    "priority": "ROUTINE"
  }'

List inbox

curl "https://www.hamlink.info/api/v1/inbox?folder=Inbox" \
  -H "Authorization: Bearer hlk_your_key"

Move to another folder, or star it

curl -X PATCH https://www.hamlink.info/api/v1/messages/MESSAGE_ID \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "folder": "Archive", "starred": true, "read": true }'

Move to Trash

curl -X DELETE https://www.hamlink.info/api/v1/messages/MESSAGE_ID \
  -H "Authorization: Bearer hlk_your_key"

Reply with POST /api/v1/messages/MESSAGE_ID/reply and { "body": "..." }. Delivery history is GET /api/v1/messages/MESSAGE_ID/events.

Devices, station, and gateway

Creating a device is the same as Settings → Devices. The secret is returned once. Do not log it in a public website.

Register a device

curl -X POST https://www.hamlink.info/api/v1/devices \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Shack PC", "platform": "windows" }'

Response

{
  "ok": true,
  "data": {
    "id": "DEVICE_ID",
    "name": "Shack PC",
    "device_public_id": "HL-NODE-...",
    "device_secret": "shown-once"
  }
}

Create a station

curl -X POST https://www.hamlink.info/api/v1/stations \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Home station",
    "callsign": "K2ABC",
    "country_code": "KW",
    "role": "PERSONAL",
    "radio_available": true,
    "internet_available": true
  }'

Update with PATCH /api/v1/stations/STATION_ID. Delete with DELETE /api/v1/stations/STATION_ID. role is PERSONAL, RELAY, or GATEWAY.

Save the regulatory profile

curl -X PUT https://www.hamlink.info/api/v1/regulatory \
  -H "Authorization: Bearer hlk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "jurisdiction": "Kuwait",
    "callsign": "K2ABC",
    "license_class": "Full",
    "allowed_bands": ["VHF", "UHF"],
    "allowed_modes": ["AX.25"],
    "gateway_permitted": true,
    "relay_permitted": true
  }'

A gateway can be created only after gateway_permitted is true. Then POST /api/v1/gateways with { "region": "Kuwait", "mode": "VHF Packet" }. Turn it off with PATCH /api/v1/gateways/GATEWAY_ID and { "enabled": false }.

Limits and errors

Each account may send 60 private requests per minute and 2000 per day. Public profile reads allow 30 per minute per visitor. Responses include X-RateLimit-Remaining and X-RateLimit-Remaining-Day.

Check what is left

curl https://www.hamlink.info/api/v1/limits \
  -H "Authorization: Bearer hlk_your_key"

Too many requests

HTTP 429
Retry-After: 48

{
  "ok": false,
  "error": "Rate limit exceeded. Try again shortly.",
  "code": "rate_limited"
}
StatusCodeMeaning
401unauthorizedMissing or invalid key
403forbiddenNot allowed, or the account is blocked
404not_foundThat record does not belong to this account
409conflictAddress or contact already exists
429rate_limitedWait for Retry-After, then try again

All routes

ActionMethod and path
Read or update profileGET or PATCH /api/v1/me
LimitsGET /api/v1/limits
Public operator cardGET /api/v1/public/operators/:callsign
AddressesGET POST /api/v1/addresses · DELETE /api/v1/addresses/:id
Inbox and messagesGET /api/v1/inbox · GET POST /api/v1/messages
One messageGET PATCH DELETE /api/v1/messages/:id
Read, reply, retry, ackPOST /api/v1/messages/:id/read|reply|retry|ack
Delivery eventsGET /api/v1/messages/:id/events
AttachmentGET /api/v1/attachments/:id
ContactsGET POST /api/v1/contacts · PATCH DELETE /api/v1/contacts/:id
NotificationsGET /api/v1/notifications · POST /api/v1/notifications/read
Route previewPOST /api/v1/route/preview
Bridge statusGET /api/v1/bridge/status
DevicesGET POST /api/v1/devices · PATCH DELETE /api/v1/devices/:id
StationsGET POST /api/v1/stations · PATCH DELETE /api/v1/stations/:id
GatewaysGET POST /api/v1/gateways · PATCH DELETE /api/v1/gateways/:id
Regulatory profileGET or PUT /api/v1/regulatory
Volunteer applicationPOST /api/v1/volunteers/apply · GET /api/v1/volunteers/me

Examples use https://www.hamlink.info. Bridge radios still use /api/agent/*.