Skip to content
Morse UniverseMorse Universe

Morse code API

Two endpoints, free and open to anyone: send text and get morse back, or send dots and dashes and get the text. JSON in, JSON out, no key and no sign-up. Build the request here and send it.

Request

curl 'https://morseuniverse.com/api/v1/encode?text=Hi'

The two endpoints

Both take GET, with the input in the query string, and POST, with a JSON body. GET is the one-line version; POST is for text long enough to be awkward in a URL. Both answer JSON on every status, including the errors.

/api/v1/encode
Turns text into morse. Takes text. The morse, in the notation you asked for.
/api/v1/decode
Reads morse back into text. Takes morse. The text, and the notation it read.

Parameters

The same names work as query parameters on a GET and as keys on a POST body. In a query string prosigns takes 1, true, 0 or false; in a body it takes a real boolean.

textencode · A string
Required. The words to send. Up to 5,000 characters.
morsedecode · A string
Required. The dots and dashes to read. Up to 5,000 characters.
notationboth · space or slash
Optional. How words are marked off. Left out, encode writes a space between letters and three between words, and decode works out which of the two it was handed.
prosignsdecode · true or false
Optional, false by default. On, a run with no gap in it is read as a prosign first, so ...-.- comes back as <SK> rather than as the letters it could also be.

What comes back

A successful answer carries both sides of the conversion, the notation it settled on, and the characters one by one. Here is GET /api/v1/encode?text=Hi in full.

{
  "text": "Hi",
  "morse": ".... ..",
  "notation": "space",
  "unknown": [],
  "tokens": [
    {
      "type": "char",
      "text": "H",
      "code": "...."
    },
    {
      "type": "char",
      "text": "I",
      "code": ".."
    }
  ],
  "table": {
    "id": "itu-latin",
    "name": "International Morse code (Latin script)",
    "source": {
      "title": "Recommendation ITU-R M.1677-1 (10/2009), International Morse code",
      "url": "https://www.itu.int/rec/R-REC-M.1677-1-200910-I/en"
    }
  }
}
text
The words: what you sent to encode, what decode made of your morse.
morse
The dots and dashes, the other way round.
notation
The notation used, whether you asked for it or the API worked it out.
unknown
Anything with no code in the table, listed in the order it turned up. An empty list means everything was sent.
tokens
One entry per character, each with its text and its code, and a space entry between words. This is what a player or a drawing reads.
table
Which code table answered, and the recommendation it comes from.

Decode answers with the same fields the other way round, plus the prosigns flag it used. This request names no notation, so the answer says which one it read:

{
  "morse": ".../---/...",
  "text": "SOS",
  "notation": "slash",
  "prosigns": false,
  "unknown": [],
  "tokens": [
    {
      "type": "char",
      "text": "S",
      "code": "..."
    },
    {
      "type": "char",
      "text": "O",
      "code": "---"
    },
    {
      "type": "char",
      "text": "S",
      "code": "..."
    }
  ],
  "table": {
    "id": "itu-latin",
    "name": "International Morse code (Latin script)",
    "source": {
      "title": "Recommendation ITU-R M.1677-1 (10/2009), International Morse code",
      "url": "https://www.itu.int/rec/R-REC-M.1677-1-200910-I/en"
    }
  }
}

Angle brackets and ampersands come back escaped, as \u003c and the like, so your own text stays inert if it lands in a page. Any JSON parser turns them back as it reads, so there is nothing to undo.

Examples

Each of these sends Hi, prints .... .., and installs nothing: curl, the browser’s own fetch, and Python’s standard library.

curl

curl 'https://morseuniverse.com/api/v1/encode?text=Hi'

curl https://morseuniverse.com/api/v1/encode \
  -H 'Content-Type: application/json' \
  -d '{"text": "Hi"}'

JavaScript

const response = await fetch('https://morseuniverse.com/api/v1/encode', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ text: 'Hi' }),
});
const { morse } = await response.json();
console.log(morse);

Python

import json
from urllib.request import Request, urlopen

body = json.dumps({"text": "Hi"}).encode()
request = Request(
    "https://morseuniverse.com/api/v1/encode",
    data=body,
    headers={"Content-Type": "application/json"},
)
with urlopen(request) as response:
    print(json.load(response)["morse"])

Limits

One request carries up to 5,000 characters, in a body of up to 64 kB. An address gets 60 requests a minute; every answer says where you stand with RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset in seconds.

Any site can call it from the browser: the answers allow every origin, and no cookie is read or set. They are also sent no-store, so nothing of yours sits in a cache on the way back.

Nothing is stored

The API keeps no log and no copy of what you send. It converts the text and answers, and that is the end of it. Our privacy page says the same for the rest of the site.

Errors

A refused request answers with the same shape every time: an error object holding a code to branch on and a message you can show someone.

{
  "error": {
    "code": "missing_text",
    "message": "No text to turn into morse. Add a text field with the words."
  }
}
400missing_text, missing_morse
Nothing to work on: the field was empty or absent.
400bad_notation, bad_prosigns
A parameter was there but wasn’t one of its values.
400bad_json, bad_text, bad_morse
The POST body wasn’t an object, or a field wasn’t a string.
405method_not_allowed
Use GET or POST. The Allow header lists the methods.
413text_too_long, morse_too_long
Over 5,000 characters. Send it in smaller pieces.
413body_too_large
Over 64 kB of body.
415bad_content_type
A POST body needs Content-Type: application/json.
429rate_limited
Over 60 requests in a minute. Retry-After says how long to wait.

Questions

Do I need an API key?

No. There is no key, no sign-up and no account: the request above is the whole thing. We ask only that you credit Morse Universe where the morse shows.

How do I convert text to morse code in Python?

Post the text to /api/v1/encode and read morse off the JSON that comes back. The Python example above does it with the standard library, so there is nothing to install.

Is there a JavaScript morse code library?

You don’t need one for this: a single fetch to /api/v1/encode gets the morse, the tokens and the timing-ready codes. To put the whole translator on a page instead, the embed code is one line of HTML.

Is there a morse code library for Arduino or Java?

Not from us, and the API is the way round it: any language that can make an HTTP request can call it, and the answer is plain JSON. On a microcontroller with no network, read the codes off the alphabet page and keep them in a table on the device.

What happens when I go over the rate limit?

The request comes back as 429 with the code rate_limited and a Retry-After header in seconds. Every other answer carries RateLimit-Remaining, so you can slow down before you get there.

Sources

More morse tools