Skip to content

Create a promoted activity — server token only

POST
/v1/promoted
curl --request POST \
--url http://localhost:3000/v1/promoted \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "actor": "example", "verb": "example", "object": "example", "custom": {}, "audience": [ "example" ], "starts_at": "2026-04-15T12:00:00Z", "expires_at": "2026-04-15T12:00:00Z" }'

Promoted content: an activity-shaped row that is served in the promoted sidecar of a feed read regardless of the follow graph and recency. Nothing is fanned out — one row serves every eligible reader, which is what makes retraction and expiry instant and free.

Targeting is the follow graph (audience), because we hold no user attributes: create a feed such as city:belgrade, follow users into it from your backend, then target that feed. Omit audience to reach everyone, including brand-new users whose feed is otherwise empty.

This is promoted content, not an ad platform: no bidding, no demographic targeting, no viewability tracking. The user-facing label (“Sponsored”, “Featured”) — and any disclosure obligation that comes with paid placement — is yours to render.

Media typeapplication/json
object
actor
required

Free-form and never overwritten — these routes are server-token only, so there is no impersonation surface. “sponsor:nike”, “system:fcurban”.

string
verb
required
string
object
required
string
custom
object
key
additional properties
any
audience

Omit or null to reach everyone. Otherwise feed refs the caller must follow — targeting is the follow graph, since we hold no user attributes (spec §5). Create a feed such as city:belgrade, follow users into it from your backend, then target it. Semantics across entries is OR. An empty array is rejected: use null for “everyone”.

array | null
>= 1 items <= 20 items
starts_at

Defaults to now. Not served before this instant.

string format: date-time
expires_at

Must be after starts_at, and in the future. Null means “until retracted”. Expiry needs no cleanup — nothing was fanned out.

string | null format: date-time
Examplegenerated
{
"actor": "example",
"verb": "example",
"object": "example",
"custom": {},
"audience": [
"example"
],
"starts_at": "2026-04-15T12:00:00Z",
"expires_at": "2026-04-15T12:00:00Z"
}

Created.

Media typeapplication/json

The full row as returned to the tenant’s backend by GET /v1/promoted.

object
id
required
string format: uuid
actor
required
string
verb
required
string
object
required
string
custom
required
object
key
additional properties
any
audience
required

Null means every user. Otherwise feed refs; a caller matching ANY of them is eligible.

Array<string> | null
starts_at
required
string format: date-time
expires_at
required
string | null format: date-time
served_count
required

Feed opens that received this row — deliveries, not views. Repeat placement within one feed session does not increment it, and a viewport impression is not observable server-side; count those client-side via the react SDK callbacks.

integer
deleted_at
required

Set when retracted. Retracted rows stay listed here but are never served.

string | null format: date-time
created_at
required
string format: date-time
Example
{
"actor": "system:fcurban",
"audience": [
"city:belgrade"
]
}

Invalid body — empty audience array (use null), more than 20 refs, a malformed feed ref, expires_at at or before starts_at or in the past.

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"
}
}

Invalid, expired, revoked, or absent token.

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 manage promoted activities — these 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"
}
}

This tenant already has 100 live (non-retracted) promoted activities. An abuse guard, not a plan limit — retract something.

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"
}
}

Rate limit exceeded.

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