KDB knowledge

Line protocol (POST /write)

Load many rows fast with the InfluxDB line format over HTTP - one line per row, answered with 204.

The line protocol is a very short text format for rows, made by InfluxDB and used by QuestDB. Each line is one row. It is faster to make and to read than INSERT statements, so it is good for live feeds (market ticks or sensor readings every second) and big loads.

live_data,symbol=CITY ltp=528.5,ltv=120i,volume=45120i 1789103700000000000

For a few rows, or rows that need SQL, use INSERT with POST /exec. More ways to load data: loading data.

Line format

Syntax:

<table>[,<tag>=<text>...] <field>=<value>[,<field>=<value>...] [<timestamp>]
PartMeaning
<table>The table name (called the "measurement" in InfluxDB). Case is ignored.
,<tag>=<text>A text value for a SYMBOL or STRING column, with no quotes. Tags come before the first space.
<field>=<value>A value for any column. Fields come after the first space, separated by commas. At least one field is needed.
<timestamp>A whole number: the time for the table's time column (the TIMESERIES(...) column). In nanoseconds unless precision= says otherwise (see the wrong unit). Without it, the server's clock is used.

Field values:

WrittenKindGoes into columns of type
512.4, -3, 1e6a decimal numberDOUBLE, FLOAT, DECIMAL
120ia whole number (i at the end)INT, LONG, SHORT, BYTE, and also DOUBLE, DECIMAL
120ua whole number without sign (u), up to 2^63-1the same as i
"text"text in double quotesSTRING, SYMBOL, JSON, BYTES, and any other type that can read that text (like INSERT does: "2026-09-11" for a DATE)
t, true, f, false (also T, True, TRUE, ...)a booleanBOOL
1789103700000000ta time in microseconds (t at the end, as QuestDB writes it). Only microseconds: see the wrong unitTIMESTAMP, DATE

Rules for writing lines:

Times in the wrong unit

A time in the wrong unit is the easiest way to load wrong data: 1757750400 read as nanoseconds is 1.7 seconds after midnight on 1 January 1970. KDB refuses such a request with 400 and says how to fix it. Nothing of the request is written.

You sendKDB answers
No precision=, and every line timestamp is before 1990 as nanoseconds, while one of them is a 1990-2200 time in seconds, milliseconds or microseconds400 timestamps look like seconds (1757750400) but precision= is not set: add ?precision=s
A t field whose number is a 1990-2200 time in seconds or milliseconds (1757750400000t)400 column 'at' cannot take 1757750400000t: a t value is microseconds, and this number looks like milliseconds ...; write 1757750400000000t
A plain whole number for a TIMESTAMP or DATE field (at=1757750400000 or at=1757750400000i)400 ... cannot take the plain number 1757750400000i: a time field needs microseconds with a t suffix (this number looks like milliseconds: write 1757750400000000t)

HTTP: Seconds without precision=: refused, nothing written (sample data: sample)

POST /write

live_data,symbol=CITY ltp=530.0 1789103700

Response:

HTTP 400 (application/json)

{
  "code": "invalid",
  "message": "error in line 1: timestamps look like seconds (1789103700) but precision= is not set: add ?precision=s (without it they are read as nanoseconds and would land on 1970-01-01T00:00:01.789Z)",
  "line": 1,
  "errorId": "d0e4b1bc074d-1"
}

HTTP: The same line with precision=s (sample data: sample)

POST /write?precision=s

live_data,symbol=CITY ltp=530.0 1789103700
###
GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z' AND symbol = 'CITY'

Response:

POST /write?precision=s

HTTP 204

GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z' AND symbol = 'CITY'

HTTP 200 (application/json)

{
  "query": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z' AND symbol = 'CITY'",
  "results": [
    {
      "statement": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z' AND symbol = 'CITY'",
      "columns": [
        {"name": "timestamp", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "ltp", "type": "DOUBLE"}
      ],
      "dataset": [
        ["2026-09-11T05:15:00.000Z", "CITY", 530]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 15, "execute_us": 89}
    }
  ],
  "timings": {"parse_us": 15, "execute_us": 89}
}

HTTP: A TIMESTAMP field in milliseconds: refused

Setup:

CREATE TABLE orders_log (time TIMESTAMP, symbol SYMBOL, placed TIMESTAMP) TIMESERIES(time) PARTITION BY DAY;
POST /write?precision=ms

orders_log,symbol=CITY placed=1789103700000t 1789103700000

Response:

HTTP 400 (application/json)

{
  "code": "invalid",
  "message": "error in line 1: table 'orders_log', column 'placed' cannot take 1789103700000t: a t value is microseconds, and this number looks like milliseconds (it would be 1970-01-21T16:58:23.700Z); write 1789103700000000t",
  "line": 1,
  "errorId": "d0e4b1bc074d-2"
}

Update some columns: upsert=merge

By default a line replaces the whole row with the same key: a column not in the line becomes its DEFAULT or NULL. With upsert=merge, a column not in the line keeps the value it has.

upsert=A column missing from the lineSpeed
replace (default)becomes DEFAULT or NULLfastest: rows are not looked up
mergekeeps its stored value; a new key is a normal insertslower: every row is looked up by its key

HTTP: Change the balance, keep the name and plan

Setup:

CREATE TABLE accounts (id LONG PRIMARY KEY, name STRING, balance DOUBLE, plan STRING DEFAULT 'free');
POST /write

accounts id=1i,name="Sita",balance=100,plan="pro"
###
POST /write?upsert=merge

accounts id=1i,balance=150
###
GET /exec?compat=0&query=SELECT id, name, balance, plan FROM accounts

Response:

POST /write

HTTP 204

POST /write?upsert=merge

HTTP 204

GET /exec?compat=0&query=SELECT id, name, balance, plan FROM accounts

HTTP 200 (application/json)

{
  "query": "SELECT id, name, balance, plan FROM accounts",
  "results": [
    {
      "statement": "SELECT id, name, balance, plan FROM accounts",
      "columns": [
        {"name": "id", "type": "LONG"},
        {"name": "name", "type": "STRING"},
        {"name": "balance", "type": "DOUBLE"},
        {"name": "plan", "type": "STRING"}
      ],
      "dataset": [
        [1, "Sita", 150, "pro"]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 56, "execute_us": 166}
    }
  ],
  "timings": {"parse_us": 56, "execute_us": 166}
}

HTTP: Without merge the missing columns are reset

Setup:

CREATE TABLE accounts (id LONG PRIMARY KEY, name STRING, balance DOUBLE, plan STRING DEFAULT 'free');
POST /write

accounts id=1i,name="Sita",balance=100,plan="pro"
###
POST /write

accounts id=1i,balance=150
###
GET /exec?compat=0&query=SELECT id, name, balance, plan FROM accounts

Response:

POST /write

HTTP 204

POST /write

HTTP 204

GET /exec?compat=0&query=SELECT id, name, balance, plan FROM accounts

HTTP 200 (application/json)

{
  "query": "SELECT id, name, balance, plan FROM accounts",
  "results": [
    {
      "statement": "SELECT id, name, balance, plan FROM accounts",
      "columns": [
        {"name": "id", "type": "LONG"},
        {"name": "name", "type": "STRING"},
        {"name": "balance", "type": "DOUBLE"},
        {"name": "plan", "type": "STRING"}
      ],
      "dataset": [
        [1, null, 150, "free"]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 23, "execute_us": 130}
    }
  ],
  "timings": {"parse_us": 23, "execute_us": 130}
}

A table that is not there

When the lines name a table the database does not have, POST /write makes it, as QuestDB does, and then writes the rows. The columns come from every line of the request for that table, in the order they first appear:

In the lineColumn type
a tag (symbol=CITY)SYMBOL
512.4DOUBLE
120iLONG
"text"STRING
t, f, true, falseBOOLEAN
1789103700000000tTIMESTAMP
the timestamp at the endthe time column timestamp (TIMESTAMP)

HTTP: A table that is not there is made from the lines

POST /write

market_index,name=MAIN value=2650.5,trades=1200i 1789103700000000000
###
GET /exec?compat=0&query=SHOW COLUMNS FROM market_index

Response:

POST /write

HTTP 204

GET /exec?compat=0&query=SHOW COLUMNS FROM market_index

HTTP 200 (application/json)

{
  "query": "SHOW COLUMNS FROM market_index",
  "results": [
    {
      "statement": "SHOW COLUMNS FROM market_index",
      "columns": [
        {"name": "name", "type": "STRING"},
        {"name": "type", "type": "STRING"},
        {"name": "primary_key", "type": "BOOL"},
        {"name": "not_null", "type": "BOOL"},
        {"name": "computed", "type": "BOOL"},
        {"name": "references", "type": "STRING"}
      ],
      "dataset": [
        ["name", "SYMBOL", false, false, false, null],
        ["value", "DOUBLE", false, false, false, null],
        ["trades", "LONG", false, false, false, null],
        ["timestamp", "TIMESTAMP", false, false, false, null]
      ],
      "count": 4,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 4, "execute_us": 9}
    }
  ],
  "timings": {"parse_us": 4, "execute_us": 9}
}

POST /write

Syntax:

POST /write[?db=<name>][&precision=n|u|ms|s][&upsert=replace|merge]
body: lines of the line protocol (UTF-8)

Parses every line, then writes all the rows in one transaction. Rows are upserted: a row with the same key as an existing row (its PRIMARY KEY or DEDUP KEY) replaces it, like INSERT OR REPLACE. So sending the same lines twice does not make duplicates in a table with a key.

ParameterWhereMeaningDefault
bodybodyThe linesrequired
dbURLThe database (or the header X-KDB-Database). InfluxDB's bucket and org are ignored.the default database
precisionURLThe unit of the timestamps at the end of the lines: n or ns nanoseconds, u or us microseconds, ms milliseconds, s seconds. Without it, timestamps that plainly are seconds, milliseconds or microseconds are refused (the wrong unit).n
upsertURLreplace: a line replaces the whole row. merge: columns missing from a line keep their stored values (merge).replace
dedupURLskip: no duplicate lookups in days that already hold rows, for trusted loads of new rows. A key already stored may then be there twice; repair with DEDUP TABLE (dedup=skip).on
waitURLtrigger: answer only after the deferred trigger jobs of these rows ended, with 200 and {"rows":N,"jobs":[...],"done":true}.no wait: 204
wait_timeoutURLWith wait=trigger: the longest wait, like 10min. Jobs still running then show "status":"running".no limit
AnswerMeaning
204 No ContentAll lines were written and are on disk. There is no body; the Server-Timing header says where the time went (timings).
code(error) "invalid" for a bad request or line, "internal error" for trouble on the server
message(error) what is wrong. About a line it starts with error in line N:
line(error) the line number (from 1), or 0 when the error is not about one line
errorId(error) a unique id of this error, to find it in logs
# Market ticks from a file, sent gzip-compressed
gzip -c ticks.lp | curl --data-binary @- -H "Content-Encoding: gzip" "http://127.0.0.1:9900/write?precision=ms"

HTTP: Three market ticks, times in seconds (sample data: sample)

POST /write?precision=s

live_data,symbol=CITY ltp=528.5,ltv=120i,volume=45120i 1789103700
live_data,symbol=COAST ltp=402.3,ltv=50i,volume=30110i 1789103700
live_data,symbol=CITY ltp=529.0,ltv=80i,volume=45200i 1789103760
###
GET /exec?compat=0&query=SELECT timestamp, symbol, ltp, ltv, volume FROM live_data WHERE timestamp >= '2026-09-11T05:15:00Z' ORDER BY timestamp, symbol

Response:

POST /write?precision=s

HTTP 204

GET /exec?compat=0&query=SELECT timestamp, symbol, ltp, ltv, volume FROM live_data WHERE timestamp >= '2026-09-11T05:15:00Z' ORDER BY timestamp, symbol

HTTP 200 (application/json)

{
  "query": "SELECT timestamp, symbol, ltp, ltv, volume FROM live_data WHERE timestamp >= '2026-09-11T05:15:00Z' ORDER BY timestamp, symbol",
  "results": [
    {
      "statement": "SELECT timestamp, symbol, ltp, ltv, volume FROM live_data WHERE timestamp >= '2026-09-11T05:15:00Z' ORDER BY timestamp, symbol",
      "columns": [
        {"name": "timestamp", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "ltp", "type": "DOUBLE"},
        {"name": "ltv", "type": "LONG"},
        {"name": "volume", "type": "LONG"}
      ],
      "dataset": [
        ["2026-09-11T05:15:00.000Z", "CITY", 528.5, 120, 45120],
        ["2026-09-11T05:15:00.000Z", "COAST", 402.3, 50, 30110],
        ["2026-09-11T05:16:00.000Z", "CITY", 529, 80, 45200]
      ],
      "count": 3,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 41, "execute_us": 108}
    }
  ],
  "timings": {"parse_us": 41, "execute_us": 108}
}

HTTP: The same moment in three precisions (sample data: sample)

POST /write

live_data,symbol=TELCO ltp=900.1 1789103700123456789
###
POST /write?precision=u

live_data,symbol=VOLT ltp=190.5 1789103700123456
###
POST /write?precision=ms

live_data,symbol=ACME ltp=250.2 1789103700123
###
GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp >= '2026-09-11' ORDER BY symbol

Response:

POST /write

HTTP 204

POST /write?precision=u

HTTP 204

POST /write?precision=ms

HTTP 204

GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp >= '2026-09-11' ORDER BY symbol

HTTP 200 (application/json)

{
  "query": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp >= '2026-09-11' ORDER BY symbol",
  "results": [
    {
      "statement": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp >= '2026-09-11' ORDER BY symbol",
      "columns": [
        {"name": "timestamp", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "ltp", "type": "DOUBLE"}
      ],
      "dataset": [
        ["2026-09-11T05:15:00.123Z", "ACME", 250.2],
        ["2026-09-11T05:15:00.123Z", "TELCO", 900.1],
        ["2026-09-11T05:15:00.123Z", "VOLT", 190.5]
      ],
      "count": 3,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 14, "execute_us": 101}
    }
  ],
  "timings": {"parse_us": 14, "execute_us": 101}
}

HTTP: Every kind of value

Setup:

CREATE TABLE feed (
  time TIMESTAMP, symbol SYMBOL, price DOUBLE, qty LONG, amount DECIMAL(2),
  final BOOL, note STRING, trade_day DATE, payload JSON
) TIMESERIES(time) PARTITION BY DAY;
POST /write?precision=ms

feed,symbol=CITY price=512.4,qty=100i,amount=51240.5,final=t,note="first, \"big\" buyer",trade_day="2026-09-11",payload="{\"broker\": 58}" 1789103700000
feed,symbol=City\ Bank price=513,qty=5u,final=false,trade_day=1789103700000000t 1789103701000
###
GET /exec?compat=0&query=SELECT * FROM feed ORDER BY time

Response:

POST /write?precision=ms

HTTP 204

GET /exec?compat=0&query=SELECT * FROM feed ORDER BY time

HTTP 200 (application/json)

{
  "query": "SELECT * FROM feed ORDER BY time",
  "results": [
    {
      "statement": "SELECT * FROM feed ORDER BY time",
      "columns": [
        {"name": "time", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "price", "type": "DOUBLE"},
        {"name": "qty", "type": "LONG"},
        {"name": "amount", "type": "DECIMAL(2)"},
        {"name": "final", "type": "BOOL"},
        {"name": "note", "type": "STRING"},
        {"name": "trade_day", "type": "DATE"},
        {"name": "payload", "type": "JSON"}
      ],
      "dataset": [
        [
          "2026-09-11T05:15:00.000Z",
          "CITY",
          512.4,
          100,
          "51240.50",
          true,
          "first, \"big\" buyer",
          "2026-09-11",
          {"broker": 58}
        ],
        ["2026-09-11T05:15:01.000Z", "City Bank", 513, 5, null, false, null, "2026-09-11", null]
      ],
      "count": 2,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 12, "execute_us": 83}
    }
  ],
  "timings": {"parse_us": 12, "execute_us": 83}
}

HTTP: Send a correction: the same key replaces the row (sample data: sample)

POST /write?precision=s

live_data,symbol=COAST ltp=402.3 1789103700
###
POST /write?precision=s

live_data,symbol=COAST ltp=402.8 1789103700
###
GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z'

Response:

POST /write?precision=s

HTTP 204

POST /write?precision=s

HTTP 204

GET /exec?compat=0&query=SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z'

HTTP 200 (application/json)

{
  "query": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z'",
  "results": [
    {
      "statement": "SELECT timestamp, symbol, ltp FROM live_data WHERE timestamp = '2026-09-11T05:15:00Z'",
      "columns": [
        {"name": "timestamp", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "ltp", "type": "DOUBLE"}
      ],
      "dataset": [
        ["2026-09-11T05:15:00.000Z", "COAST", 402.8]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 16, "execute_us": 115}
    }
  ],
  "timings": {"parse_us": 16, "execute_us": 115}
}

HTTP: Line 2 is wrong: nothing is written (sample data: sample; shows an error)

POST /write?precision=s

live_data,symbol=CITY ltp=530.0 1789103820
live_data,symbol=COAST ltp=403.0,volume=12.5 1789103820
live_data,symbol=TELCO ltp=901.0 1789103820
###
GET /exec?compat=0&query=SELECT count(*) AS rows_at_05_17 FROM live_data WHERE timestamp = '2026-09-11T05:17:00Z'

Response:

POST /write?precision=s

HTTP 400 (application/json)

{
  "code": "invalid",
  "message": "error in line 2: table 'live_data', column 'volume' is LONG and cannot take a float; write whole numbers with an i suffix, like 3i",
  "line": 2,
  "errorId": "d0e4b1bc074d-3"
}

GET /exec?compat=0&query=SELECT count(*) AS rows_at_05_17 FROM live_data WHERE timestamp = '2026-09-11T05:17:00Z'

HTTP 200 (application/json)

{
  "query": "SELECT count(*) AS rows_at_05_17 FROM live_data WHERE timestamp = '2026-09-11T05:17:00Z'",
  "results": [
    {
      "statement": "SELECT count(*) AS rows_at_05_17 FROM live_data WHERE timestamp = '2026-09-11T05:17:00Z'",
      "columns": [
        {"name": "rows_at_05_17", "type": "LONG"}
      ],
      "dataset": [
        [0]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 15, "execute_us": 75}
    }
  ],
  "timings": {"parse_us": 15, "execute_us": 75}
}

HTTP: Every column must exist (sample data: sample)

POST /write

live_data,symbol=CITY ltp=530.0,turnover=1250000.5 1789103700000000000

Response:

HTTP 400 (application/json)

{
  "code": "invalid",
  "message": "error in line 1: table 'live_data' has no column 'turnover'; add it first (ALTER TABLE live_data ADD COLUMN ...)",
  "line": 1,
  "errorId": "d0e4b1bc074d-4"
}

HTTP: A trigger runs once for the whole request (sample data: sample)

Setup:

CREATE TABLE write_log (id INT PRIMARY KEY AUTO, rows_written LONG);
CREATE TRIGGER count_ticks AFTER INSERT ON live_data EXECUTE BEGIN
  FOR r IN (SELECT count(*) AS n FROM NEW) DO
    INSERT INTO write_log (rows_written) VALUES (r.n);
  END FOR;
END;
POST /write?precision=s

live_data,symbol=CITY ltp=531.0 1789104000
live_data,symbol=COAST ltp=404.0 1789104000
live_data,symbol=TELCO ltp=902.0 1789104000
###
GET /exec?compat=0&query=SELECT * FROM write_log

Response:

POST /write?precision=s

HTTP 204

GET /exec?compat=0&query=SELECT * FROM write_log

HTTP 200 (application/json)

{
  "query": "SELECT * FROM write_log",
  "results": [
    {
      "statement": "SELECT * FROM write_log",
      "columns": [
        {"name": "id", "type": "INT"},
        {"name": "rows_written", "type": "LONG"}
      ],
      "dataset": [
        [1, 3]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 12, "execute_us": 84}
    }
  ],
  "timings": {"parse_us": 12, "execute_us": 84}
}

HTTP: Bad precision

POST /write?precision=minutes

live_data,symbol=CITY ltp=530.0 1

Response:

HTTP 400 (application/json)

{
  "code": "invalid",
  "message": "unsupported precision 'minutes': use n, u, ms or s",
  "line": 0,
  "errorId": "d0e4b1bc074d-5"
}

HTTP: Writing needs POST

GET /write

Response:

HTTP 405 (application/json)

{"error": "method GET is not allowed here"}

Clients (not run by the help build):

curl -s -i "http://127.0.0.1:9900/write?db=market&precision=s" --data-binary @ticks.lp
# Send a file of lines. -i shows the 204 status; on an error the JSON says which line.
$lines = Get-Content ticks.lp -Raw
Invoke-WebRequest -Method Post -Uri "http://127.0.0.1:9900/write?db=market&precision=s" -Body $lines -ContentType "text/plain; charset=utf-8" |
  Select-Object StatusCode
import time
import requests

def write_ticks(ticks, db="market"):
    # ticks: list of (symbol, ltp, volume). One request for all of them.
    now = int(time.time())
    body = "\n".join(f"live_data,symbol={s} ltp={ltp},volume={vol}i {now}" for s, ltp, vol in ticks)
    r = requests.post("http://127.0.0.1:9900/write", params={"db": db, "precision": "s"},
                      data=body.encode("utf-8"))
    if r.status_code != 204:
        e = r.json()
        raise RuntimeError(f"line {e['line']}: {e['message']}")

write_ticks([("CITY", 528.5, 45120), ("COAST", 402.3, 30110)])
// Node 18+: a live feed that sends the ticks of each second in one request.
const lines = ticks.map((t) => `live_data,symbol=${t.symbol} ltp=${t.ltp},volume=${t.volume}i ${t.timeMs}`).join("\n");
const res = await fetch("http://127.0.0.1:9900/write?db=market&precision=ms", { method: "POST", body: lines });
if (res.status !== 204) {
  const e = await res.json();
  throw new Error(`line ${e.line}: ${e.message}`);
}
using var http = new HttpClient();
var body = new StringContent("live_data,symbol=CITY ltp=528.5,volume=45120i 1789103700\n", Encoding.UTF8, "text/plain");
var res = await http.PostAsync("http://127.0.0.1:9900/write?db=market&precision=s", body);
if ((int)res.StatusCode != 204) Console.WriteLine(await res.Content.ReadAsStringAsync());

POST /api/v2/write

Syntax:

POST /api/v2/write[?db=<name>][&precision=n|u|ms|s]
body: lines of the line protocol

The same as POST /write, at the path InfluxDB 2 clients use. Everything (parameters, answers, errors) is the same.

ParameterWhereMeaningDefault
dbURLThe database (or the header X-KDB-Database). bucket and org are ignored.the default database
precisionURLn, u, ms or s (also ns, us)n
AnswerMeaning
204, or {"code", "message", "line", "errorId"}as for POST /write

HTTP: The InfluxDB 2 path (sample data: sample)

POST /api/v2/write?db=demo&precision=ms&bucket=ignored

live_data,symbol=VOLT ltp=191.0,volume=70500i 1789103700000
###
GET /exec?compat=0&query=SELECT timestamp, symbol, ltp, volume FROM live_data WHERE symbol = 'VOLT' AND timestamp >= '2026-09-11'

Response:

POST /api/v2/write?db=demo&precision=ms&bucket=ignored

HTTP 204

GET /exec?compat=0&query=SELECT timestamp, symbol, ltp, volume FROM live_data WHERE symbol = 'VOLT' AND timestamp >= '2026-09-11'

HTTP 200 (application/json)

{
  "query": "SELECT timestamp, symbol, ltp, volume FROM live_data WHERE symbol = 'VOLT' AND timestamp >= '2026-09-11'",
  "results": [
    {
      "statement": "SELECT timestamp, symbol, ltp, volume FROM live_data WHERE symbol = 'VOLT' AND timestamp >= '2026-09-11'",
      "columns": [
        {"name": "timestamp", "type": "TIMESTAMP"},
        {"name": "symbol", "type": "SYMBOL"},
        {"name": "ltp", "type": "DOUBLE"},
        {"name": "volume", "type": "LONG"}
      ],
      "dataset": [
        ["2026-09-11T05:15:00.000Z", "VOLT", 191, 70500]
      ],
      "count": 1,
      "truncated": false,
      "rows_affected": 0,
      "message": "",
      "timings": {"parse_us": 23, "execute_us": 119}
    }
  ],
  "timings": {"parse_us": 23, "execute_us": 119}
}