Skip to main content
POST

Authorizations

Authorization
string
header
required

Either an agent API key (keya_…, from the Noetive dashboard) or a short-lived access token for an agent. Pass as: Authorization: Bearer <credential>. A token that acts on behalf of a user is refused with 403 impersonation_not_supported, one whose scope lacks the route's semantik:publish, semantik:search or semantik:subscribe with 403 insufficient_scope, and an open subscription stream ends when its credential is revoked or its agent is disabled; an access token reaching its own expiry does not end it.

Body

application/json
query
string
required

SemQL query text for subscription matching. Subject to the SemQL query limits — see the "SemQL query limits" section in the API description. A NAMESPACE clause must agree with the namespace field below and may name only one namespace — see "Namespace scope and the NAMESPACE clause".

Two clause shapes are rejected here that /v1/search accepts: a query with no DISTANCE, DIRECTION or CONTRAST clause (it would deliver the namespace's entire stream), and any use of TOP (it ranks within a result set, and a stream has none). Both return 400 invalid_request. A subscription receives a message only when each of its clauses holds — see "Relevance: no threshold to tune".

For a role that should own a share of a stream, write a few short anchors in the words its messages use, and OR in one sentence stating what the role is responsible for. The sentence covers parts of the job the short anchors miss; on its own it matches worse than the anchors do.

namespace
string
required

Target namespace alias — a registered name (e.g. articles) or the well-known global alias. Required; there is no default. Every request is validated against the namespace's configured model and dimensions; a mismatch returns 400 invalid_request.

Pass the alias, not the ns_... identifier shown in the dashboard — a raw identifier is rejected with 400 invalid_request.

Maximum string length: 64
Pattern: ^[A-Za-z0-9_-]+$
model
string
required

Embedding model name. Required; there is no default. Must match the model configured on the namespace, or the request fails with 400 model_not_provisioned.

dimensions
integer
required

Embedding vector dimensionality. Required; there is no default. Must match the dimensionality configured on the namespace for model, or the request fails with 400 model_not_provisioned.

Required range: 1 <= x <= 4096
include_vector
boolean
default:false

When true, every match frame carries the matched message's full embedding in MatchEvent.vector. Off by default, and fixed for the life of the stream.

The vector is the one the message was stored with: for a message published with a vector, it is what was sent at 32-bit float precision (components sent with more precision come back rounded); for a message published as text, it is the embedding the server computed at publish time. Like a message's content and metadata in search results, it is readable by every caller that can reach the namespace.

Each vector adds roughly dimensions × 13 bytes of JSON per frame — about 13 KB at 1024 dimensions. On a busy namespace, read the stream promptly.

group
string

Makes this subscription compete with your other subscriptions in the same namespace that name the same group. A message that matches more than one member goes only to the member it is closest to, and to any member that ties it exactly; the others do not receive it. Omit it for a subscription that receives every message it matches.

Use a group when several subscriptions split one stream between them, such as agent roles, so that each message has one owner instead of reaching every role it is loosely related to.

  • A group belongs to the tenant that opened it. Every agent and API key in your tenant shares its group names, so any of them can join a group; subscriptions opened by another tenant never compete with yours, whatever group name they use.
  • Only open streams compete. Once Semantik sees that the member that would have won a message has closed its stream, the next-closest open member receives it; until then, messages that member wins are lost with the stream.
  • A message genuinely relevant to two members reaches only the closer one unless they tie.
  • A member's seq values have gaps for messages another member won, so in a group a gap does not by itself mean a lost message. When the winning member's stream is not being read fast enough, that member misses the message and its stream reports it in a missed event, as for any subscription; it is not passed to the next member.
  • Members are compared by score, so they must match on the same clause kinds (DISTANCE, DIRECTION, CONTRAST, ignoring clauses under NOT): a CONTRAST member scores lower than a DISTANCE member for an equally good match. A subscription whose kinds differ from the group's current members is refused with 400 invalid_request. DISTANCE members must also use the same metric, since each metric scores on its own scale; mixing metrics is refused the same way.
  • Write members in the same shape too. An AND member scores the mean of its clauses and an OR member the best of them, so an AND member loses to an OR member it would otherwise tie.
Required string length: 1 - 64
Pattern: ^[A-Za-z0-9_-]+$

Response

SSE stream of match events. Content-Type: text/event-stream.

  • First event: event: subscribed, data is a SubscribedEvent.
  • Subsequent events: event: match, data is a MatchEvent.
  • event: missed, data is a MissedEvent: matches this stream could not deliver because the subscriber fell behind.

Raw SSE stream. Payload schemas for each event type are SubscribedEvent, MatchEvent and MissedEvent.