Skip to content

Batch import activities — server token only

POST
/v1/batch/activities
curl --request POST \
--url http://localhost:3000/v1/batch/activities \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "activities": [ { "feed": "user:alice", "activity": { "actor": "example", "verb": "example", "object": "example", "target": "example", "foreign_id": "example", "time": "2026-04-15T12:00:00Z", "custom": {}, "refs": [ "example" ] } } ] }'

Cold-start import: add up to 100 activities in one call. Each item carries the destination feed ref inline plus the existing add body; activity.time (existing optional field) carries historical timestamps, passed through unclamped as for any server-token add. Quiet — fan-out runs normally but writes no live-mode head keys, and no webhooks are fired. Idempotent when items supply foreign_id + time (existing dedupe identity) — a rerun returns the existing rows without a second fan-out; without it a rerun duplicates. Partial failure still returns 200 — inspect per-item results.

Media typeapplication/json
object
activities
required
Array<object>
>= 1 items <= 100 items
object
feed
required
string
Example
user:alice
activity
required
object
actor

Ignored and overwritten for user tokens (spec §5).

string
verb
required
string
object
required
string
target
string | null
foreign_id

Requires time when present — VALIDATION_FAILED otherwise. Dedupe is on the (foreign_id, time) pair; a foreign_id without a caller-pinned time can never dedupe (each retry would get a fresh server timestamp, silently duplicating), so the API rejects the combination rather than letting an idempotency assumption fail quietly. Deliberate safety deviation from GetStream.

string | null
time

For user tokens, clamped to [now - 10 min, now] (spec §5): retries with the same (foreign_id, time) dedupe; future-pinning is impossible. Server tokens pass it through unclamped. Required when foreign_id is set.

string format: date-time
custom
object
key
additional properties
any
refs

Objects this activity points at, as type:id. Max 4, no duplicates.

Array<string>

Envelope accepted. Per-item results, ordered and same-length as the input; a failed item never rolls back the rest.

Media typeapplication/json
object
results
required
Array<object>
object
index
required
integer
ok
required
boolean
id

Present when ok for users/activities

string
code

§8 error code, present when not ok

string
Examplegenerated
{
"results": [
{
"index": 1,
"ok": true,
"id": "example",
"code": "example"
}
]
}

Envelope invalid (0 items, more than 100 items, or malformed shape).

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

User tokens cannot import — batch routes are server token only.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

Batch rate limit exceeded. Batch routes charge a separate 600 requests/min window per tenant — never the normal tenant limit.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}
Retry-After
integer