Send data with the HTTP ingest API

Push readings from any script, gateway or service with one HTTPS call.

The ingest API is one endpoint, POST /v1/ingest. Anything that can make an HTTPS request can use it: scripts, edge gateways, PLC bridges, cloud functions and integration tools.

Set up

  1. Create the site and machines

    Create them in the app or with POST /v1/sites and POST /v1/machines. Set each machine's externalId to the name your source uses (for example B-101), so messages can address it without knowing InduQT ids.

  2. Create an API key

    In Settings → API keys, create a key with the ingest scope, limited to the site the data belongs to. See site-scoped keys.

  3. Send a reading

    Name the machine by id or externalId and send numeric values by signal key.

POST /v1/ingest
curl -X POST "https://api.induqt.ai/v1/ingest" \
  -H "Authorization: Bearer $INDUQT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "machine": "B-101",
  "siteId": "6f1c2c0e-4b1a-4c55-9d0e-1f2a3b4c5d6e",
  "ts": "2026-10-27T03:12:09Z",
  "values": {
    "steam_pressure": 112.4,
    "steam_flow": 2.1,
    "flue_o2": 3.2,
    "stack_temp": 410
  }
}'
Response
{
  "accepted": 4,
  "rejected": 0,
  "machines": [
    "0b7d9a12-7c3e-4f10-a2b4-c5d6e7f8a9b0"
  ]
}

Body fields

Ingest body fields
NameTypeDescription
machinestringMachine id or its externalId. Required unless each reading names its machine.
siteIdstringNeeded to resolve an externalId when the key is not tied to one site.
tsISO 8601 string | epoch millisecondsReading time. Default: time received.
valuesobject of number | booleanSignal key → value. Keys: letters, digits, _ . - (max 64). Booleans become 0/1; numeric strings are parsed.
readingsarrayBatch form: [{ machine?, ts?, values }].
autoCreatebooleanCreate a machine (family "other") for an unknown externalId at the site. Counts towards the plan.
  • Use a key with the ingest scope. A site-scoped key can only write to that site.
  • Unknown machines are counted in rejected with a reason in errors[]; if nothing is accepted the response is 400.
  • Readings for the same machine, signal and timestamp overwrite each other, so retries are safe.
  • Rate limit: 600 requests a minute per key. Batch when sending more than a few readings a second.

Batches

To send several readings, or several machines, in one request use readings. Each reading can name its own machine and time; ts takes ISO 8601 or epoch milliseconds.

Batch body
{
  "siteId": "6f1c2c0e-4b1a-4c55-9d0e-1f2a3b4c5d6e",
  "readings": [
    {
      "machine": "B-101",
      "ts": "2026-10-27T03:12:00Z",
      "values": {
        "steam_pressure": 112.1,
        "steam_flow": 2.08
      }
    },
    {
      "machine": "B-101",
      "ts": "2026-10-27T03:12:05Z",
      "values": {
        "steam_pressure": 112.4,
        "steam_flow": 2.1
      }
    },
    {
      "machine": "B-102",
      "ts": 1793070725000,
      "values": {
        "steam_pressure": 98.7,
        "burner_on": 1
      }
    }
  ]
}

Examples

Python (requests)
import os, requests

r = requests.post(
    "https://api.induqt.ai/v1/ingest",
    headers={"Authorization": f"Bearer {os.environ['INDUQT_API_KEY']}"},
    json={"machine": "B-101", "values": {"steam_pressure": 112.4, "steam_flow": 2.1}},
    timeout=10,
)
r.raise_for_status()
print(r.json())  # {'accepted': 2, 'rejected': 0, ...}
Node.js 18+ (fetch)
const res = await fetch('https://api.induqt.ai/v1/ingest', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.INDUQT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ machine: 'B-101', values: { steam_pressure: 112.4, steam_flow: 2.1 } }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());

Ignition, Kepware, AWS IoT and webhooks

These have no dedicated connector; they send the same ingest body over HTTPS.

Ignition

Run a gateway timer script (for example every 5 s) that reads tags and posts them. Keep the key out of project exports.

Ignition gateway timer script (Jython)
paths = ["[default]Boiler/B-101/SteamPressure", "[default]Boiler/B-101/SteamFlow"]
keys = ["steam_pressure", "steam_flow"]
qvs = system.tag.readBlocking(paths)
values = dict((k, qv.value) for k, qv in zip(keys, qvs) if qv.quality.isGood())

client = system.net.httpClient()
client.post("https://api.induqt.ai/v1/ingest",
    data={"machine": "B-101", "values": values},
    headers={"Authorization": "Bearer " + system.tag.readBlocking(["[default]Config/InduQTKey"])[0].value})

Kepware

Use the IoT Gateway REST client agent pointed at https://api.induqt.ai/v1/ingest with an Authorization: Bearer header, and a message template that produces { "machine": …, "values": { … } }. Where a custom template is not available, read Kepware with Node-RED or OPC UA instead.

AWS IoT Core

Add a rule (for example SELECT * FROM 'plant/+/telemetry') whose action invokes a small Lambda function that reshapes the message and posts it to the ingest API with the key from Secrets Manager.

Webhooks and integration tools

Zapier, Make, Power Automate, n8n or a vendor webhook: send a POST to https://api.induqt.ai/v1/ingest with the bearer header and the JSON body above.

Troubleshooting

Troubleshooting
SymptomLikely cause and fix
401 UnauthorizedThe header is missing or the key was revoked. The header must be exactly Authorization: Bearer iq_live_…
403 ForbiddenThe key lacks the ingest scope, or is limited to a different site than the machine.
Readings rejected or machine not foundThe externalId is not known at the site. Check the spelling, send siteId (or use a site-scoped key), or set autoCreate: true.
Values missingOnly numbers (and booleans, stored as 0/1) are kept. Strings such as "112.4 psig" are rejected: send 112.4.
Times look shiftedA ts without a zone is ambiguous. Send UTC with Z, an explicit offset, or epoch milliseconds.
429 Too Many RequestsMore than the rate limit. Buffer and send batches, and see retries.