curl --request POST \
--url https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '"<unknown>"'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify('<unknown>')
};
fetch('https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset}"
payload = "<unknown>"
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"submission_id": "<string>",
"idempotent": true
}{
"submission_id": "<string>",
"routed": [
"<string>"
],
"records": 123
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}Ingest an event with an ingest key straight into a named dataset
curl --request POST \
--url https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '"<unknown>"'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify('<unknown>')
};
fetch('https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.hookie.ai/v1/ingest/{ingest_key}/{dataset}"
payload = "<unknown>"
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"submission_id": "<string>",
"idempotent": true
}{
"submission_id": "<string>",
"routed": [
"<string>"
],
"records": 123
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}{
"error": "<string>",
"retry_after": 123,
"upgrade_url": "<string>"
}Authorizations
An ik_live_… ingest key. Stored hashed; the plaintext is returned once at creation.
Headers
Optional; a repeat key short-circuits with 200 before quota is charged.
Required only when the key has require_signature. Format 't=,v1=', v1 = HMAC-SHA-256 over '.'.
Path Parameters
The plaintext ingest key (prefix lookup + constant-time SHA-256 comparison; revoked keys never match).
Dataset name. Its presence switches routing to identity: the whole payload is stored as one record in this dataset and the project's mapping rules are NOT consulted. The name is used as given (no validation, no lookup) and it overrides the key's dataset_default.
Body
Form encodings are flattened (repeats become arrays, file parts become {filename, type, size} with the bytes discarded); every other Content-Type is parsed as JSON; an empty body becomes {}. On this route a payload that is not a JSON object (array or scalar) is wrapped as {"value": } before it is stored. Over 1,000,000 bytes yields 413.
Any JSON value; objects are stored field-for-field, arrays and scalars are wrapped as {value: }.
Response
Idempotent replay — a submission with this Idempotency-Key already exists for the tenant. No quota is charged when the duplicate is detected up front; a request that loses the unique-index race has already been counted against the monthly quota.