Postlad/Guides/Point your ThingSpeak sketch at Postlad

Point your ThingSpeak sketch at Postlad

Postlad's device host answers /update and /update.json, and on those two paths it accepts api_key and field1field16 as well as its own parameter names. A sketch that already builds a ThingSpeak write URL moves by changing the hostname and the key. Nothing else in the request has to change.

The same request, a different hostA board sends one HTTP GET whose query string is unchanged; only the hostname and the key differ, and the reply is a Postlad sentence rather than a number.your boardunchanged sketchone HTTP GETwasapi.thingspeak.comnowapi.postlad.comok 1?api_key=…&field1=23.5
The query string survives the move. The reply does not: Postlad answers ok 1, not an entry number.

The change, in full

Here are the two URLs beside each other. Everything after the host is the same string:

text
Before: https://api.thingspeak.com/update?api_key=OLD_KEY&field1=23.5&field2=61
After:  http://api.postlad.com/update?api_key=YOUR_POSTLAD_KEY&field1=23.5&field2=61

Two things to notice. The key is a different key — Postlad write keys look like pk_live_… and are minted on your stream page. And the scheme is http, which is deliberate: plain HTTP is a first-class route here, because a sketch that opens with https:// is a sketch that fails on the older board it was written for. HTTPS works too; see plain HTTP and when not to use it.

The two lines in the sketch

In a typical Arduino-style sketch that builds the URL itself, the diff is two constants:

cpp
// was
const char* HOST_URL  = "https://api.thingspeak.com/update";
const char* WRITE_KEY  = "OLD_THINGSPEAK_KEY";

// now
const char* HOST_URL  = "http://api.postlad.com/update";
const char* WRITE_KEY  = "pk_live_YOUR_KEY";

The line that assembles the query does not change:

cpp
String url = String(HOST_URL)
           + "?api_key=" + WRITE_KEY
           + "&field1=" + String(temperature, 2)
           + "&field2=" + String(humidity, 1);

Upload it, open the serial monitor, and the first successful line reads HTTP 200 with a body of ok followed by a number — ok 1 on an account that has stored nothing else this month.

What the reply says now

This is the one real divergence, and it is deliberate. The alias accepts ThingSpeak's parameter names; it does not imitate ThingSpeak's response. A Postlad write answers with a Postlad reply — ok <n> on success, or a status code of 400 or more with one sentence naming what was wrong.

What your sketch does with the replyWhat you have to change
Ignores it — fire and forgetNothing
Checks the HTTP status codeNothing. 200 means the reading is stored; 400 and above mean it is not
Parses the body as a numberOne line. The body is the text ok and a number, which does not parse as a number on its own
Reads JSON from /update.jsonThe key names. They are ok, stored, month_points, stream and ts

A JSON reply looks like this:

json
{"ok":true,"stored":1,"month_points":4021,"stream":"greenhouse","ts":1754604000000}

There is no entry id in it, and no row number a chart depends on. stored is how many readings this request added, and month_points is how many your account has stored this month — both facts about your data rather than positions in our storage.

The number in the plain-text ok <n> is that same monthly count, which is worth knowing if your sketch logs it: it climbs as you send and resets on the 1st, so it is a usage meter and not an id you can store against a reading.

The rule behind the divergence. Postlad never answers 200 for a reading it did not store. If you want one line of certainty in a sketch, print the status code and the body together; between them they always say what happened.

What the alias accepts

You sendPostlad reads it as
api_keyk, the stream's write key
field1field16f1f16
THINGSPEAKAPIKEY request headerThe write key, and it wins over a key in the query
statusA short status string, up to 120 bytes, shown on the stream page
tA device timestamp in unix seconds or milliseconds
fmt=text or fmt=jsonThe reply format you want, whichever path you called

Four more details worth knowing before you change anything:

  • Sixteen fields, not eight. field9 through field16 are real here and map to f9f16.
  • GET and POST both work. A form-encoded POST /update body is read the same way as a query string, which is what several Arduino HTTP libraries produce.
  • Parameter names are case-folded. API_KEY and Field1 are accepted, because a library that title-cases form keys has not made a typo.
  • /update.json answers JSON and /update answers plain text, unless an explicit fmt= says otherwise.

The alias is a widening rather than a replacement. Postlad's own names work on the same path, so http://api.postlad.com/update?k=KEY&f1=23.5 is equally valid and you can migrate the parameter names later, or never.

What it refuses, out loud

Postlad stores numbers and one short status string. Anything else in the query — a location, an elevation, a social-posting parameter an older sketch may still carry — is refused with a 400 that names it, rather than accepted and dropped:

text
HTTP 400
error unknown_param: "lat" is not a parameter Postlad understands.
Valid: api_key or k, field1..field16 or f1..f16, t, status, fmt.

That is the same rule everywhere on this API, and it exists because the alternative is worse: a request that returns ok while quietly discarding half of what you sent produces a stream that stays empty and an afternoon spent looking for the reason. The refusals you are most likely to meet while migrating:

StatusMeansFix
400 unknown_paramA parameter Postlad does not storeRemove it. The sentence names the valid set in both dialects
400 bad_valueA field carried something that is not a plain decimalSend 23.5, not 23.5C. The error names the field as f1, the name it is stored under
401 bad_keyThe key is not one of oursPaste the pk_live_… key from your stream page
429 rate_limitedReadings arriving faster than the plan acceptsSlow the loop and honour Retry-After. The point was not stored, and the sentence says so

If your sketch uses the ThingSpeak Arduino library

Then the alias does not help you, and it would be dishonest to imply otherwise. A sketch built on ThingSpeak.setField() and ThingSpeak.writeFields() is not sending a URL you can repoint — the library is. Replacing that call with a plain HTTP request is about ten lines:

cpp
#include <WiFi.h>
#include <HTTPClient.h>

const char* WRITE_KEY = "pk_live_YOUR_KEY";

void sendReading(float temperature, float humidity) {
  HTTPClient http;
  String url = String("http://api.postlad.com/u?k=") + WRITE_KEY
             + "&f1=" + String(temperature, 2)
             + "&f2=" + String(humidity, 1);

  http.begin(url);
  int status = http.GET();
  Serial.printf("HTTP %d %s\n", status, http.getString().c_str());
  http.end();
}

That is the whole client. There is no library to install, no broker to stand up and no auth header to construct. Send ESP32 data to the cloud has the complete sketch with WiFi handling and a DHT22 version.

What you get on the free plan

  • One reading every 5 seconds, with a burst of two — two writes may arrive back to back, and the next one has to wait for the interval. A write that arrives early is refused with a 429 that names the interval and says how many seconds to wait.
  • 100,000 stored readings a month, counted per account.
  • Two streams, sixteen fields each.
  • Every reading kept at full detail for 30 days. After that it becomes an hourly minimum, maximum and average, kept for 12 months. Older than that is deleted.
  • Public share links and embeds — a viewer needs no account, and free-tier embeds carry a small Postlad badge.
  • CSV export on every plan, at any time.
  • No non-commercial restriction. The plans differ on the numbers in the pricing table and on nothing else.

The last two lines are the ones worth reading twice if you are here because of a licence rather than a rate limit. When we checked MathWorks' own pages on 6 August 2026, ThingSpeak's free licence was described as non-commercial use only, and its documented minimum update interval on the free tier was 15 seconds.

Where ThingSpeak is still ahead

Two places, and pretending otherwise would make the rest of this page worth less.

The free message allowance is larger. ThingSpeak's pricing page described the free tier as fewer than 3 million messages a year when we checked it on 6 August 2026 — roughly 8,200 a day. Postlad's free plan stores 100,000 readings a month, which is about 1.2 million a year. If your project needs volume more than it needs speed, that difference is real. Our answer is the 5-second interval, the 12-month history and a $6 plan rather than a bigger free number we would have to fund.

MATLAB. ThingSpeak's analysis and visualisation are MATLAB, and Postlad has no equivalent and is not building one. What we do instead is give the data back: CSV export on every plan, and a JSON read API for scripts.

One thing worth stating plainly rather than leaving as an insinuation: when we loaded thingspeak.mathworks.com/prices on 6 August 2026, the free-tier description rendered an unreplaced template placeholder, and the paid licence prices were not shown on the page. We recorded it because a buyer deserves to know a price is unavailable before they plan around it, not as a verdict on the service behind it.

Bring the history with you

The sketch is one half. If the channel holds readings you want to keep, export it first: ThingSpeak's Data Import / Export tab produces a CSV, and Postlad's importer recognises the created_at,entry_id,field1…field8 shape and preserves the timestamps. Export ThingSpeak data to CSV and move the history is the step-by-step version, including what happens to readings older than the retention window.

Do the export before you change the device. It costs nothing to have the file and everything to want it later.

Check it worked, then stop the old one

  1. Send one reading and read the reply. HTTP 200 with ok 1 means it is stored.
  2. Open the stream page and confirm the value and the timestamp are the ones you sent.
  3. Name the fields and units on the stream page — f1 becomes Temperature, °C. Naming affects the chart, the CSV and the share page, never the device request.
  4. Leave both destinations configured for a day if the readings matter. Two HTTP requests per loop is a small price for a rollback that is one constant long.
  5. Set a stream-goes-quiet alert so that the next silence reaches you as an email rather than as a gap you notice in a fortnight.

Rolling back is the same edit in reverse. Nothing here holds your device hostage, and nothing here holds your data hostage either — the export button is on the stream page from the first reading onward.

Plain HTTP, and when not to use it

Postlad accepts plain HTTP as a first-class route rather than as a grudging fallback, because "works from the dumbest possible client" is the point of the product. The trade-off is equally plain: anybody who can observe that network can read the reading and the write key.

Use HTTPS when the data or the key is sensitive, or when the board can afford proper certificate validation. A houseplant and a laboratory freezer do not have the same threat model. A stream can also be set to require HTTPS, in which case a plain request to it is refused rather than quietly downgraded.

FAQ

Is Postlad a drop-in ThingSpeak replacement?

For the write path, close to it: the same query string works after a hostname and key change, and sixteen fields are available instead of eight. For everything else, no — the reply is a Postlad reply, the dashboard is different, and there is no MATLAB. This page lists every divergence we know of rather than leaving them to be discovered.

Do I have to rename field1 to f1?

No. field1field16 keep working on /update and /update.json for as long as those paths exist. Postlad's own /u endpoint takes f1f16, and it will tell you so if you send a field1 there by habit.

What happens to location parameters?

They are refused with a 400 naming the parameter. Postlad stores numeric time series and a short status string; a coordinate silently discarded is exactly the failure the refusal exists to prevent. If a coordinate is genuinely part of the measurement, send it as a numeric field.

Can I send my own timestamp?

Yes — t=, in unix seconds or milliseconds, within 7 days of now. Leave it off and the server timestamps the reading on arrival. For a backlog after an outage, send the readings together through the batch endpoint: store and forward after an outage.

Does the alias have its own rate limit?

No, and that is on purpose. /update reaches the same handler, the same limits and the same quota as /u. It is a set of parameter names, not a second door with different rules.

Where are the API docs?

At app.postlad.com/docs/api, with the error catalogue at /docs/errors.

Create the stream

Signup is an email address and a magic link. The write key is waiting on the other side, and the sketch change is the two constants above.

Create your free account →

Sources and verification

  • Postlad behaviour on this page was read from the shipped ingest worker and its test suite: the alias paths, the parameter mapping, the header form of the key, the reply shapes and the shared rate limiter.
  • ThingSpeak free-tier facts — non-commercial licence, fewer than 3 million messages a year, a 15-second minimum update interval, prices absent from the pricing page and an unreplaced template placeholder in the free-tier description — were checked directly against MathWorks' pages on 6 August 2026 and are reported as of that date.
  • MathWorks, ThingSpeak write data: https://www.mathworks.com/help/thingspeak/writedata.html