Data sources
A data source is where your raw observations live. This page covers Temporis's data model and how to send data into it well.
You create a data source once in the dashboard, then stream observations into it over the API as they happen.
The data model
Temporis stores data as rows. Every observation is a single triple: when something was measured, what was measured, and the number you measured.
orders or revenue.A single data source can hold many named series side by side. The name field is what keeps them apart. Your data is isolated from every other customer's — a data source belongs to you alone.
Creating a data source
You create a data source in the dashboard under Data Sources. Give it a name and it is ready to receive data.
Names follow a few rules:
- Start with a lowercase letter.
- Use only lowercase letters, digits, and underscores.
- Up to 48 characters.
So store_metrics and grid_load_eu are valid; Store-Metrics and 2024data are not. A freshly created data source is empty until you send it observations.
Sending observations
You add data with the ingest endpoint. Each call carries the target data_source and a list of records. Here we push a few orders readings into store_metrics.
curl -X POST https://api.temporis.co/v1/data_sources/ingest \
-H "Authorization: Bearer ts_<token>" \
-H "Content-Type: application/json" \
-d '{
"data_source": "store_metrics",
"records": [
{ "timestamp": 1718870400, "name": "orders", "value": 42 },
{ "timestamp": 1718874000, "name": "orders", "value": 51 },
{ "timestamp": 1718877600, "name": "orders", "value": 47 }
]
}'import requests
requests.post(
"https://api.temporis.co/v1/data_sources/ingest",
headers={"Authorization": "Bearer ts_<token>"},
json={
"data_source": "store_metrics",
"records": [
{"timestamp": 1718870400, "name": "orders", "value": 42},
{"timestamp": 1718874000, "name": "orders", "value": 51},
{"timestamp": 1718877600, "name": "orders", "value": 47},
],
},
) # -> 204 No Contentawait fetch("https://api.temporis.co/v1/data_sources/ingest", {
method: "POST",
headers: {
"Authorization": "Bearer ts_<token>",
"Content-Type": "application/json",
},
body: JSON.stringify({
data_source: "store_metrics",
records: [
{ timestamp: 1718870400, name: "orders", value: 42 },
{ timestamp: 1718874000, name: "orders", value: 51 },
{ timestamp: 1718877600, name: "orders", value: 47 },
],
}),
}); // -> 204 No ContentA successful ingest returns HTTP 204 No Content with an empty body — there is nothing to read back, the rows are simply stored. See the ingest reference for the full request and error details.
Many series in one source
You are not limited to one series per source. Send different name values into the same data_source and they coexist as separate series. A store might track orders, revenue, and visitors all in store_metrics.
{
"data_source": "store_metrics",
"records": [
{ "timestamp": 1718870400, "name": "orders", "value": 42 },
{ "timestamp": 1718870400, "name": "revenue", "value": 1284.50 }
]
}Keeping related series together is convenient and lets you forecast them jointly later. A data profile is where you choose which of these names to actually read.
Updates and backfills
The upsert key is the pair (timestamp, name). Sending a record whose timestamp and name already exist overwrites the stored value rather than adding a duplicate.
Because writes are idempotent on (timestamp, name), you can replay a batch after a network hiccup, correct a wrong reading, or load months of history in any order — the result is always the same final value per bucket.
Archiving
When a source is no longer collecting new data, you can archive it in the dashboard. Archiving stops further ingestion: a request targeting an archived source returns HTTP 409 "Data source is archived."
Archiving is non-destructive. Existing data stays put, and any data profiles built on the source keep working against the data already stored.