curl --request POST \
--url https://api.example.com/v0/admin/plugins \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"idempotency_key": "<string>",
"endpoint": "<string>",
"manifest": "<string>",
"configuration": {},
"routes": [
{
"media_type": "<string>"
}
],
"kinds": [
"<string>"
],
"spaces": {}
}
'import requests
url = "https://api.example.com/v0/admin/plugins"
payload = {
"idempotency_key": "<string>",
"endpoint": "<string>",
"manifest": "<string>",
"configuration": {},
"routes": [{ "media_type": "<string>" }],
"kinds": ["<string>"],
"spaces": {}
}
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({
idempotency_key: '<string>',
endpoint: '<string>',
manifest: '<string>',
configuration: {},
routes: [{media_type: '<string>'}],
kinds: ['<string>'],
spaces: {}
})
};
fetch('https://api.example.com/v0/admin/plugins', 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.example.com/v0/admin/plugins",
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([
'idempotency_key' => '<string>',
'endpoint' => '<string>',
'manifest' => '<string>',
'configuration' => [
],
'routes' => [
[
'media_type' => '<string>'
]
],
'kinds' => [
'<string>'
],
'spaces' => [
]
]),
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.example.com/v0/admin/plugins"
payload := strings.NewReader("{\n \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\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.example.com/v0/admin/plugins")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/admin/plugins")
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 \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\n}"
response = http.request(request)
puts response.read_body{
"registration_id": "<string>",
"plugin_id": "<string>",
"version": "<string>",
"endpoint": "<string>",
"manifest_digest": "<string>",
"contributions": [
"<string>"
],
"roles": [
"<string>"
],
"state": "registered",
"pinned_work": 1,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"artifact_digest": "<string>",
"check": {
"certified": true,
"checked_at": "2023-11-07T05:31:56Z",
"passed": 1,
"failed": 1,
"skipped": 1,
"checks": [
{
"id": "<string>",
"title": "<string>",
"status": "pass",
"issues": [
{
"code": "<string>",
"message": "<string>",
"path": "<string>"
}
],
"contribution": "<string>"
}
]
}
}{
"code": "<string>",
"message": "<string>",
"retryable": true,
"field": "<string>",
"resync_url": "<string>"
}Register plugin
Register a plugin version the operator runs at an address. The request carries the exact quivr-plugin.yaml the plugin was built from, its endpoint and the settings it is installed with, with the shape and rules of a pin in the startup configuration (configuration, routes, kinds, spaces); plugin id and version come from the manifest. Quivr then checks it in the background with the Contract Runner against the endpoint, whose discovery must report the manifest’s digest. The registration is registered while its check runs, then validated or rejected with the report. The same idempotency key returns the same registration; a key already used for another registration is 409 idempotency_conflict; a new key for a rejected registration checks it again. 422 invalid_plugin lists what the engine refuses in the manifest or settings. Requires plugins:admin.
curl --request POST \
--url https://api.example.com/v0/admin/plugins \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"idempotency_key": "<string>",
"endpoint": "<string>",
"manifest": "<string>",
"configuration": {},
"routes": [
{
"media_type": "<string>"
}
],
"kinds": [
"<string>"
],
"spaces": {}
}
'import requests
url = "https://api.example.com/v0/admin/plugins"
payload = {
"idempotency_key": "<string>",
"endpoint": "<string>",
"manifest": "<string>",
"configuration": {},
"routes": [{ "media_type": "<string>" }],
"kinds": ["<string>"],
"spaces": {}
}
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({
idempotency_key: '<string>',
endpoint: '<string>',
manifest: '<string>',
configuration: {},
routes: [{media_type: '<string>'}],
kinds: ['<string>'],
spaces: {}
})
};
fetch('https://api.example.com/v0/admin/plugins', 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.example.com/v0/admin/plugins",
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([
'idempotency_key' => '<string>',
'endpoint' => '<string>',
'manifest' => '<string>',
'configuration' => [
],
'routes' => [
[
'media_type' => '<string>'
]
],
'kinds' => [
'<string>'
],
'spaces' => [
]
]),
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.example.com/v0/admin/plugins"
payload := strings.NewReader("{\n \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\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.example.com/v0/admin/plugins")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/admin/plugins")
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 \"idempotency_key\": \"<string>\",\n \"endpoint\": \"<string>\",\n \"manifest\": \"<string>\",\n \"configuration\": {},\n \"routes\": [\n {\n \"media_type\": \"<string>\"\n }\n ],\n \"kinds\": [\n \"<string>\"\n ],\n \"spaces\": {}\n}"
response = http.request(request)
puts response.read_body{
"registration_id": "<string>",
"plugin_id": "<string>",
"version": "<string>",
"endpoint": "<string>",
"manifest_digest": "<string>",
"contributions": [
"<string>"
],
"roles": [
"<string>"
],
"state": "registered",
"pinned_work": 1,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"artifact_digest": "<string>",
"check": {
"certified": true,
"checked_at": "2023-11-07T05:31:56Z",
"passed": 1,
"failed": 1,
"skipped": 1,
"checks": [
{
"id": "<string>",
"title": "<string>",
"status": "pass",
"issues": [
{
"code": "<string>",
"message": "<string>",
"path": "<string>"
}
],
"contribution": "<string>"
}
]
}
}{
"code": "<string>",
"message": "<string>",
"retryable": true,
"field": "<string>",
"resync_url": "<string>"
}Authorizations
API key, not necessarily a JWT. Server derives Organization, permitted actions and Corpus scope; every resource access is authorized.
Body
1 - 200Base URL where the operator runs the plugin, such as http://127.0.0.1:9900. A connector plugin needs https unless it is on loopback.
1 - 2048The exact text of the quivr-plugin.yaml the plugin was built from; its sha256 must be the manifest digest the plugin's discovery reports.
1 - 262144Plugin configuration, validated against the manifest's configuration schema.
Media types routed to the plugin's normalizer.
100Show child attributes
Show child attributes
Alert kinds offered, a subset of those the manifest declares; absent offers them all.
1001Vector spaces of an ingestion plugin by space id, served or evaluation; absent serves the only declared space.
Show child attributes
Show child attributes
Response
Successful response
111Base URL where the operator runs this plugin version.
11Roles the manifest declares it can serve, such as normalizer:application/pdf, subscription: or connector:. The active plan says which it serves.
registered while the Contract Runner checks it, then validated or rejected; active while the active plan names it. Once a later plan leaves it out it is draining while pinned_work is above zero, then inactive.
registered, validated, active, draining, inactive, rejected Unfinished work pinned to a Pipeline Plan that names this registration, such as the processing of a receipt, a connector run or a rebuild. Work finishes on the plan it started on, so a registration a plan change left out keeps being called until this reaches zero.
x >= 0Artifact digest the plugin reports, recorded as information. Absent when it reports none.
1What the Contract Runner reported on a registration; certified plugins are validated.
Show child attributes
Show child attributes