curl --request POST \
--url https://api.vainona.ai/v1/namespaces/{ns}/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"filters": {},
"events": [
"entered"
],
"include": {
"attributes": [
"<string>"
],
"answers": [
"<string>"
]
},
"endpoint": "<string>",
"bulk": "summary"
}
'import requests
url = "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions"
payload = {
"name": "<string>",
"filters": {},
"events": ["entered"],
"include": {
"attributes": ["<string>"],
"answers": ["<string>"]
},
"endpoint": "<string>",
"bulk": "summary"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
filters: {},
events: ['entered'],
include: {attributes: ['<string>'], answers: ['<string>']},
endpoint: '<string>',
bulk: 'summary'
})
};
fetch('https://api.vainona.ai/v1/namespaces/{ns}/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'filters' => [
],
'events' => [
'entered'
],
'include' => [
'attributes' => [
'<string>'
],
'answers' => [
'<string>'
]
],
'endpoint' => '<string>',
'bulk' => 'summary'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vainona.ai/v1/namespaces/{ns}/subscriptions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vainona.ai/v1/namespaces/{ns}/subscriptions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"filters": {
"[1]": "Eq"
},
"events": [
"entered"
],
"include": {
"attributes": [
"<string>"
],
"answers": [
"<string>"
]
},
"endpoint": "<string>",
"bulk": "summary",
"status": "syncing",
"live_at": "2023-11-07T05:31:56Z",
"lag_ms": 1,
"warnings": [
{
"code": "judgment_inactive",
"message": "<string>",
"judgment": "<string>"
}
],
"created_at": "2023-11-07T05:31:56Z",
"template": "<string>"
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}Create a subscription
A subscription is a saved query: a filters expression in the query
grammar (§6.8), with the same meaning, and the fields to include. It
sends subscription.entered when a document starts matching and,
if asked, subscription.exited when it stops, to endpoint and to
the events feed. It sees only settled answers: a document whose
answers the filter reads are pending waits until they land.
On a template prefix (acme%2Fprod%2F*) it applies to every
namespace under the prefix, including ones created later, which
needs templates (Team and above; plan_required below). Each event
names the tenant namespace and where the subscription was
defined_on.
Refused with invalid_request: a filter on any
answers.<j>.freshness (a subscription only sees settled answers),
a judgment in filters or include that doesn’t exist or is
on_read, more than 24 fields, a name the namespace already has or
inherits, an endpoint the organization doesn’t have or whose
namespace_prefix does not cover the namespace or template, and a
101st subscription in a namespace, counting inherited ones. A create
that repeats an existing subscription’s settings under its name is
a retry and returns it. If the endpoint can’t be checked right now
the create is unavailable; retry it. The filter can’t be changed
later: create a new subscription and delete the old one.
It starts syncing: its first pass records which documents match
now without sending events for them, then it is live. Bulk
changes (backfills, threshold edits, new composite weights) update
membership silently and send one subscription.synced, unless
bulk is deliver.
curl --request POST \
--url https://api.vainona.ai/v1/namespaces/{ns}/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"filters": {},
"events": [
"entered"
],
"include": {
"attributes": [
"<string>"
],
"answers": [
"<string>"
]
},
"endpoint": "<string>",
"bulk": "summary"
}
'import requests
url = "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions"
payload = {
"name": "<string>",
"filters": {},
"events": ["entered"],
"include": {
"attributes": ["<string>"],
"answers": ["<string>"]
},
"endpoint": "<string>",
"bulk": "summary"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
filters: {},
events: ['entered'],
include: {attributes: ['<string>'], answers: ['<string>']},
endpoint: '<string>',
bulk: 'summary'
})
};
fetch('https://api.vainona.ai/v1/namespaces/{ns}/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'filters' => [
],
'events' => [
'entered'
],
'include' => [
'attributes' => [
'<string>'
],
'answers' => [
'<string>'
]
],
'endpoint' => '<string>',
'bulk' => 'summary'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vainona.ai/v1/namespaces/{ns}/subscriptions"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vainona.ai/v1/namespaces/{ns}/subscriptions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vainona.ai/v1/namespaces/{ns}/subscriptions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"filters\": {},\n \"events\": [\n \"entered\"\n ],\n \"include\": {\n \"attributes\": [\n \"<string>\"\n ],\n \"answers\": [\n \"<string>\"\n ]\n },\n \"endpoint\": \"<string>\",\n \"bulk\": \"summary\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"filters": {
"[1]": "Eq"
},
"events": [
"entered"
],
"include": {
"attributes": [
"<string>"
],
"answers": [
"<string>"
]
},
"endpoint": "<string>",
"bulk": "summary",
"status": "syncing",
"live_at": "2023-11-07T05:31:56Z",
"lag_ms": 1,
"warnings": [
{
"code": "judgment_inactive",
"message": "<string>",
"judgment": "<string>"
}
],
"created_at": "2023-11-07T05:31:56Z",
"template": "<string>"
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}{
"error": {
"code": "invalid_request",
"message": "<string>",
"details": {
"suggested_context": {
"recipe": {
"fields": [
"<string>"
],
"last_n": {},
"window": {},
"max_tokens": 2,
"related": {}
},
"cost_per_answer": 1,
"whole_state_cost_per_answer": 1,
"sampled_documents": 2,
"excluded": [
{
"path": "<string>",
"reason": "id"
}
]
}
}
}
}Authorizations
An organization API key. Keys carry a role (read_write or
read_only) and may be restricted to a namespace prefix such as
acme/*, or to one namespace such as acme/prod/tenant_1. A prefix
matches on a / boundary: acme/prod/tenant_1* covers
acme/prod/tenant_1 and everything under acme/prod/tenant_1/,
never acme/prod/tenant_12.
Headers
Returns the original response verbatim while the node still caches it. Correctness never depends on it.
1Path Parameters
A namespace name, or a template prefix ending in /* (§7.7), with any
/ sent as %2F: acme%2Fprod%2Ftenant_123 or acme%2Fprod%2F*.
A namespace name, or a template prefix: a namespace path ending in
/*, such as acme/prod/*, which every namespace under acme/prod/
inherits judgments from (§7.7). Up to 256 bytes.
1 - 256^[A-Za-z0-9._:/-]+(/\*)?$Body
A judgment, attribute or threshold name. Names are path segments in field references, so they never contain ..
1 - 128^[A-Za-z0-9_-]+$The query's filter grammar (§6.8), with its missing-field rules. Never on answers.<j>.freshness, and never on an on_read judgment. It can't be changed later.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
Show child attributes
Show child attributes
1entered when a document starts matching; exited when it stops matching or is deleted.
entered, exited The attributes and answers each event carries. The fields the
filter reads are always included, and state never is. At most 24
fields in all, counting those the filter reads. An on_read
judgment is refused.
Show child attributes
Show child attributes
The webhook endpoint that receives the events. Null, the default, sends them to the events feed only. Its namespace_prefix must cover the namespace or template.
^we_[0-9a-z]{26}$What bulk changes send: a backfill, the first sync, or a resync
after a threshold edit, an activation or new composite weights.
summary updates membership silently and sends one
subscription.synced. deliver sends every transition, with its
cause.
summary, deliver Response
Created.
^sub_[0-9a-z]{26}$A judgment, attribute or threshold name. Names are path segments in field references, so they never contain ..
1 - 128^[A-Za-z0-9_-]+$[field, op, value], ["And" | "Or", [filters]] or ["Not", filter].
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
Show child attributes
Show child attributes
entered when a document starts matching; exited when it stops matching or is deleted.
entered, exited The attributes and answers each event carries. The fields the
filter reads are always included, and state never is. At most 24
fields in all, counting those the filter reads. An on_read
judgment is refused.
Show child attributes
Show child attributes
^we_[0-9a-z]{26}$What bulk changes send: a backfill, the first sync, or a resync
after a threshold edit, an activation or new composite weights.
summary updates membership silently and sends one
subscription.synced. deliver sends every transition, with its
cause.
summary, deliver In this namespace. Null on a template's prefix path, where each namespace syncs on its first change after the subscription exists.
syncing, live When the subscription went live in this namespace.
How long the oldest change the subscription has not evaluated yet has waited, in milliseconds; 0 when it is up to date. A quiet subscription records its progress about once a minute, so a change counts only once it has waited longer than that. Null while syncing and on a template's prefix path.
x >= 0Show child attributes
Show child attributes
RFC 3339, UTC.
Present when the subscription is inherited, the template prefix it comes from, such as acme/prod/*.
3 - 256^[A-Za-z0-9._:/-]+/\*$