Inovacc Desarrolladores

Referencia de la API

Conocimiento y búsqueda vectorial

Ingesta documentos, arma colecciones de conocimiento y consúltalas por significado.

URL base https://ai.inovacc.dev

Descripción general

Conocimiento y búsqueda vectorial mantiene el conocimiento de tu organización donde una aplicación puede hacerle preguntas por significado. Tiene tres partes, todas en https://ai.inovacc.dev:

  • la Vector Database (base de datos vectorial): un almacén administrado de pasajes de texto que ingestas y buscas, con filtros, ámbitos y reordenamiento opcional;
  • las colecciones de conocimiento: envía un lote de archivos mixtos (documentos, imágenes, video) y haz que se procesen en paquetes de conocimiento; luego descarga el resultado, consúltalo, chatea con él con citas, o haz que se redacte un informe sobre él;
  • los trabajos de conocimiento: convierten una grabación larga en una base de conocimiento que descargas como un solo archivo comprimido.

El problema que resuelve es todo lo que hay entre "tenemos archivos" y "el asistente puede responder a partir de ellos": extraer texto, cortarlo en pasajes, generar embeddings, indexar, mantener el índice consistente y citar la fuente de cada respuesta. Inovacc hace esos pasos y tú llamas a un puñado de endpoints.

Úsalo cuando las respuestas deban salir de tu propio material. Si ya ejecutas tu propio índice vectorial, los Embeddings de IA te dan solo los vectores. Cuando la respuesta es texto libre sin fuentes, usa el Chat con IA. Inovacc habilita cada parte para tu organización; una parte que no está habilitada responde 403 (vector_database_disabled, collections_disabled o knowledge_disabled).

Conceptos

Vector Database y su perfil. Tu organización crea una base de datos con POST /v1/vector/databases, eligiendo un perfil de embeddings de GET /v1/vector/profiles. Un perfil indica la modalidad (text), los idiomas (english o multilingual), las dimensiones y la métrica de distancia; los ids se ven como text-multilingual-1024. Eliges un perfil, nunca un modelo. El perfil no puede cambiar: para usar otro, elimina la base de datos, crea una nueva e ingesta de nuevo.

Documentos, ámbitos y modos. Ingestas pasajes con tu propio id, su text y metadata plana opcional. Un pasaje va a un ámbito: shared (todos los servicios del espacio de trabajo de tu organización) o local (solo la clave de API que lo escribió). Las consultas toman un modo: shared, local, o hybrid para buscar en ambos y combinar por puntuación. Se puede filtrar por seis claves de metadatos: kind, source, category, tag, language, created_at. Los fragmentos que comparten un document_id forman un documento con una generation (tu número de versión), lo que permite eliminar o reemplazar un documento completo de una vez.

Colecciones y su modo. Una colección se crea en uno de tres modos, fijos durante toda su vida: download (procesa archivos, descarga los paquetes y luego no queda nada), cloud (Inovacc conserva el contenido procesado y sus vectores para que puedas ejecutar query, chat y un analysis) o local_vectors (Inovacc conserva solo vectores, nunca texto: tú haces embed de tus propios fragmentos y query devuelve ids de fragmentos y puntuaciones). Las colecciones se conservan 30 días por defecto; una organización configurada en retención zero las tiene eliminadas una hora después de que empieza la descarga.

Elementos. Un archivo se une a una colección en la solicitud (hasta 16 MiB), desde una carga completada (video de más de 16 MiB), por URL pública, o por una URL firmada sellada a una clave de un solo uso para que nunca se almacene. Cada elemento pasa por queued, processing, y luego done o failed; un elemento fallido no detiene a los demás.

Consistencia eventual y searchable. El índice vectorial aplica las escrituras de forma asíncrona: un vector se puede leer unos segundos, a veces minutos, después de haberse escrito. GET /v1/vector/databases y toda respuesta de colección reportan searchable; una consulta enviada mientras es false puede omitir los pasajes más recientes. El indexing.complete de una colección cloud es true solo cuando cada fragmento está escrito y se puede leer.

Trabajos, potencia y presupuesto. Un trabajo de conocimiento toma una carga completada de una grabación, una transcripción y notas opcionales, un power (light, medium o max) y un max_price_usd obligatorio. Un trabajo que supera el tope de tu organización se rechaza antes de cualquier trabajo de pago.

Cómo funciona

Toda llamada lleva Authorization: Bearer <key>. Tu organización se obtiene de la clave. X-Operation-Id es obligatorio en las llamadas POST de colecciones, cargas y trabajos y las hace idempotentes: un reintento con el mismo id devuelve la primera respuesta (X-Idempotent-Replay: true) y no agrega nada; el mismo id con un archivo distinto es 409 operation_id_reused. En la Vector Database es opcional, porque la ingesta y la eliminación son idempotentes por construcción: ingestar un id existente lo reemplaza.

Una consulta (POST /v1/vector/query) toma mode, query (de 1 a 8,000 caracteres), top_k (de 1 a 50) y un filter opcional; devuelve las coincidencias de mejor a peor, cada una con id, score, text y metadata. Con "retrieval": "vector_rerank" y un rerank_profile, una lista de candidatos más amplia es reordenada por una etapa de reordenamiento; el objeto retrieval de la respuesta indica si el reordenamiento se aplicó o si se recurrió al orden vectorial.

Una colección funciona en pasos que puedes observar: créala, agrega elementos (202, queued), léela hasta que status sea complete, y luego descarga, consulta o chatea. Leer una colección cloud también avanza su indexación, una cantidad acotada por llamada, y cada respuesta lleva el progreso de indexing. chat responde solo a partir de las fuentes recuperadas, numera cada cita con el elemento, el paquete, el fragmento y el localizador, y dice que no puede responder cuando las fuentes no cubren la pregunta. Un analysis se construye a lo largo de varias solicitudes: repite POST o GET cada pocos segundos hasta que responda 200 con el informe.

Un trabajo es asíncrono: POST /v1/knowledge/jobs responde 202 con job_id, status_url y poll_after_seconds (también como Retry-After). Lee el estado cuando se te indique; la plataforma pronostica el tiempo hasta terminar e incluye eta_seconds mientras puede. Cuando state es done, descarga el archivo comprimido; se conserva 24 horas.

Lo que se mide: tokens de embeddings y vectores escritos por ingesta e indexación, consultas, reordenamientos como su propia unidad, llamadas de chat en tu ruta de chat, y trabajos por su precio. POST /v1/knowledge/estimates calcula el precio de una grabación antes de que la cargues, sin costo.

Primeros pasos

Necesitas una clave de API y la parte que quieras habilitada para tu organización (Autenticación).

  1. Crea la base de datos. GET /v1/vector/profiles, elige un perfil y luego POST /v1/vector/databases con {"profile":"<id>"}. La respuesta es 201 con la base de datos.
  2. Ingesta pasajes. POST /v1/vector/ingest con "scope":"shared" y dos o tres documentos (consulta los ejemplos). La respuesta indica cuántos se ingested y lista los skipped con un motivo.
  3. Espera a searchable. GET /v1/vector/databases hasta que searchable sea true.
  4. Consulta. POST /v1/vector/query con "mode":"shared" y una pregunta redactada de forma distinta a tus pasajes. El pasaje más cercano aparece primero, con su score.
  5. Prueba una colección. POST /v1/collections con {"mode":"cloud"}, agrega un PDF a /items, lee la colección hasta que indexing.complete sea true, y luego POST /v1/collections/{id}/chat y revisa las citations.

Casos de uso

Un asistente basado en tu manual. Tu intranet ingesta cada página de políticas como fragmentos bajo su document_id, con metadatos de category. El asistente consulta con un filtro de category y pasa los mejores pasajes a su propio prompt. Cuando una página cambia, se ingesta de nuevo con una generation mayor, y los fragmentos que la nueva versión ya no tiene dejan de aparecer de inmediato.

Preguntas sobre los archivos entregados por un cliente. Un consultor crea una colección cloud por proyecto, agrega los contratos y las hojas de cálculo que envió el cliente, y hace preguntas mediante chat. Cada respuesta cita el elemento y la página en que se apoya, de modo que cada afirmación se puede verificar antes de pasar a un informe; analysis produce un resumen, entidades y contradicciones entre los archivos.

De grabaciones de reuniones a una base de conocimiento. Después de cada reunión grabada, la aplicación estima el precio, carga el video en partes de 64 MiB con la propia transcripción de la llamada como referencia, e inicia un trabajo con max_price_usd. Cuando el trabajo está done, el archivo comprimido (audio, fotogramas clave y la base de conocimiento) se archiva junto con la reunión.

Límites y precios

LímiteValor
Cuerpo de solicitud de la Vector Database1 MiB
Documentos por ingesta, ids por eliminación100
Un documento (id + text + metadata)10 KiB
Texto de consulta; top_k8,000 caracteres; 50
Valores de $in en un filtro20
Elemento en el cuerpo de una solicitud, u obtenido por URL16 MiB
Elementos por colección100; 1 GiB de archivos enviados en solicitudes; 20 GiB de video por carga
top_k de consulta de colección; mensajes de chat20; de 1 a 20 mensajes de hasta 8,000 caracteres
Fragmentos por llamada embed100, cada uno de hasta 8,000 caracteres
Llamadas al modelo de análisis por informe32
Tamaño de las partes de una carga64 MiB (todas las partes menos la última)
Carga que no es video (transcripción, notas)16 MiB
Carga de grabaciónel tope de tu organización
Claves de obtención sin usar16, cada una válida una vez durante 60 segundos
Resultado del trabajo conservado24 horas
Retención de colecciones30 días por defecto

Precios: a consultar. Una grabación procesada por un trabajo se cobra en minutos de video, y POST /v1/knowledge/estimates devuelve su precio línea por línea antes de que cargues cualquier cosa. El chat sobre una colección se mide como el Chat con IA en tu ruta de chat.

Errores

EstadoCódigoQué significa y qué hacer
400invalid_body, unsupported_fieldUn campo o valor que la ruta no acepta; revisa los campos de la ruta.
400invalid_profileElige un perfil listado por GET /v1/vector/profiles.
400confirmation_requiredEliminar la base de datos requiere {"confirm":"delete-database-and-all-vectors"}.
400invalid_url, signed_url_must_be_sealedSolo URL https públicas en el puerto 443; una URL firmada debe estar sellada.
400fetch_key_invalid, invalid_sealed_urlSolicita una nueva clave de obtención y sella de nuevo.
403vector_database_disabled, collections_disabled, knowledge_disabledEsa parte no está habilitada para tu organización.
403budget_exceededEl max_price_usd del trabajo supera el tope de tu organización.
404collection_not_found, job_not_found, upload_not_found, analysis_not_foundRevisa el id; la descarga de un trabajo también es 404 hasta que está done.
409vector_database_not_created, vector_database_exists, vector_database_deletingCrea primero la base de datos; una por organización; espera a que termine una eliminación.
409mode_not_supportedLa operación no existe en el modo de esta colección.
409collection_incomplete, collection_fullEspera a que terminen los elementos; la colección está en su límite.
409upload_incomplete, operation_id_reused, operation_in_progressTermina la carga; usa un nuevo id de operación para un archivo distinto; espera.
410collection_expired, result_expiredLa retención terminó; procesa de nuevo.
413request_too_large, url_too_largeUsa POST /v1/uploads para archivos grandes.
415, 422unsupported_media_type, input_rejected, archive_rejectedEl tipo de archivo no se lee, o el archivo fue rechazado (reason indica por qué).
429too_many_fetch_keys y los códigos de cuotaUsa o deja vencer las claves que tienes; consulta Errores.
502, 504url_fetch_failed, url_fetch_timeout, upstream_error, timeout_errorFalló la URL o el procesamiento; reintenta.
503service_unavailableReintenta más tarde; no se adivinó nada.

Buenas prácticas

  • Agrupa los fragmentos bajo un document_id y aumenta generation cuando cambie la fuente; la eliminación y el reemplazo funcionan entonces por documento.
  • Envía content_sha256 con cada fragmento y compáralo con GET /v1/vector/documents para resincronizar tu copia sin volver a ingestar todo.
  • Revisa searchable (o indexing.complete) antes de confiar en los pasajes más recientes.
  • Mantén la respuesta de un pasaje dentro de sus primeros 2,000 caracteres cuando uses reordenamiento; el reordenador solo lee esa cantidad.
  • Compara vector_rerank con vector simple en tus propios datos, sobre todo fuera del inglés, antes de depender de él.
  • Estima siempre antes de un trabajo y configura max_price_usd; consulta el estado en poll_after_seconds, no más rápido.
  • Sella las URL firmadas; nunca envíes una URL que lleve un inicio de sesión. Carga los bytes en su lugar.
  • Revisa las citas: un modelo puede citar una fuente real para algo que esa fuente no dice.

Autenticación

Toda llamada lleva tu clave; tu organización viene de ella. Consulta la guía de autenticación.

EncabezadoAuthorizationBearer <clave de API>
EncabezadoX-Operation-Idun id único que tú eliges, en toda llamada excepto GET

Endpoints

POST /v1/vector/ingest

POST /v1/vector/query

POST /v1/collections

POST /v1/collections/{id}/query

POST /v1/knowledge/jobs

Ejemplo

Lenguaje

⋮
POST /v1/vector/ingestEjemplo

cURL

curl -X POST "https://ai.inovacc.dev/v1/vector/ingest" \
  -H "Authorization: Bearer $INOVACC_API_KEY" \
  -H "X-Operation-Id: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
}'

TypeScript

import crypto from "node:crypto";

const body: Record<string, unknown> = {
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
};

const url = "https://ai.inovacc.dev/v1/vector/ingest";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

Python

import json
import os
import urllib.request
import uuid

body = {
    "scope": "shared",
    "documents": [
        {
            "id": "handbook-leave-1",
            "text": "Employees accrue two and a half days of paid leave per month.",
            "metadata": {
                "category": "hr",
            },
            "document_id": "handbook-leave",
            "generation": 1,
        },
    ],
}

request = urllib.request.Request(
    "https://ai.inovacc.dev/v1/vector/ingest",
    data=json.dumps(body).encode(),
    method="POST",
    headers={
        "User-Agent": "inovacc-python-sample",
        "Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
        "X-Operation-Id": str(uuid.uuid4()),
        "Content-Type": "application/json",
    },
)

with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Go

package main

import (
	"crypto/rand"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

const url = "https://ai.inovacc.dev/v1/vector/ingest"

const body = `{
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
}`

// newUUID returns a random (version 4) UUID, from the standard library alone.
func newUUID() string {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		panic(err)
	}
	b[6] = b[6]&0x0f | 0x40
	b[8] = b[8]&0x3f | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

func main() {
	req, err := http.NewRequest("POST", url, strings.NewReader(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
	req.Header.Set("X-Operation-Id", newUUID())
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(res.Status, string(out))
}

Rust

// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// Cargo.toml: serde_json = "1"
// Cargo.toml: uuid = { version = "1", features = ["v4"] }

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("INOVACC_API_KEY")?;
    let body = serde_json::json!({
        "scope": "shared",
        "documents": [
            {
                "id": "handbook-leave-1",
                "text": "Employees accrue two and a half days of paid leave per month.",
                "metadata": {
                    "category": "hr"
                },
                "document_id": "handbook-leave",
                "generation": 1
            }
        ]
    });
    let response = reqwest::blocking::Client::new()
        .post("https://ai.inovacc.dev/v1/vector/ingest")
        .bearer_auth(api_key)
        .header("X-Operation-Id", uuid::Uuid::new_v4().to_string())
        .json(&body)
        .send()?;
    println!("{} {}", response.status(), response.text()?);
    Ok(())
}

JavaScript

import crypto from "node:crypto";

const body = {
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
};

const url = "https://ai.inovacc.dev/v1/vector/ingest";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

PHP

<?php

$body = <<<'JSON'
{
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
}
JSON;

function uuid4(): string
{
    $bytes = random_bytes(16);
    $bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40);
    $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
}

$curl = curl_init('https://ai.inovacc.dev/v1/vector/ingest');
curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
        'X-Operation-Id: ' . uuid4(),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);

Ruby

require "net/http"
require "securerandom"
require "uri"

uri = URI('https://ai.inovacc.dev/v1/vector/ingest')
body = <<~'JSON'
{
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
}
JSON

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
request["X-Operation-Id"] = SecureRandom.uuid
request["Content-Type"] = "application/json"
request.body = body

response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts "#{response.code} #{response.body}"

Java

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;

public class Main {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("INOVACC_API_KEY");
        String body = "{" +
                "\"scope\": \"shared\"," +
                "\"documents\": [" +
                "{" +
                "\"id\": \"handbook-leave-1\"," +
                "\"text\": \"Employees accrue two and a half days of paid leave per month.\"," +
                "\"metadata\": {" +
                "\"category\": \"hr\"" +
                "}," +
                "\"document_id\": \"handbook-leave\"," +
                "\"generation\": 1" +
                "}" +
                "]" +
                "}";

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://ai.inovacc.dev/v1/vector/ingest"))
                .header("Authorization", "Bearer " + apiKey)
                .header("X-Operation-Id", UUID.randomUUID().toString())
                .header("Content-Type", "application/json")
                .method("POST", HttpRequest.BodyPublishers.ofString(body))
                .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() + " " + response.body());
    }
}

C#

using System.Text;

var body = "{" +
    "\"scope\": \"shared\"," +
    "\"documents\": [" +
    "{" +
    "\"id\": \"handbook-leave-1\"," +
    "\"text\": \"Employees accrue two and a half days of paid leave per month.\"," +
    "\"metadata\": {" +
    "\"category\": \"hr\"" +
    "}," +
    "\"document_id\": \"handbook-leave\"," +
    "\"generation\": 1" +
    "}" +
    "]" +
    "}";

var url = "https://ai.inovacc.dev/v1/vector/ingest";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Headers.Add("X-Operation-Id", Guid.NewGuid().ToString());
request.Content = new StringContent(body, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");

Kotlin

import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.util.UUID

fun main() {
    val apiKey = System.getenv("INOVACC_API_KEY")
    val body = "{" +
        "\"scope\": \"shared\"," +
        "\"documents\": [" +
        "{" +
        "\"id\": \"handbook-leave-1\"," +
        "\"text\": \"Employees accrue two and a half days of paid leave per month.\"," +
        "\"metadata\": {" +
        "\"category\": \"hr\"" +
        "}," +
        "\"document_id\": \"handbook-leave\"," +
        "\"generation\": 1" +
        "}" +
        "]" +
        "}"

    val request = HttpRequest.newBuilder()
        .uri(URI.create("https://ai.inovacc.dev/v1/vector/ingest"))
        .header("Authorization", "Bearer " + apiKey)
        .header("X-Operation-Id", UUID.randomUUID().toString())
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(body))
        .build()

    val response = HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString())
    println("${response.statusCode()} ${response.body()}")
}

Swift

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let body = #"""
{
  "scope": "shared",
  "documents": [
    {
      "id": "handbook-leave-1",
      "text": "Employees accrue two and a half days of paid leave per month.",
      "metadata": {
        "category": "hr"
      },
      "document_id": "handbook-leave",
      "generation": 1
    }
  ]
}
"""#

let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""

let url = URL(string: "https://ai.inovacc.dev/v1/vector/ingest")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Operation-Id")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(body.utf8)

let (data, response) = try await URLSession.shared.data(for: request)
let status = (response as? HTTPURLResponse)?.statusCode ?? 0
print(status, String(decoding: data, as: UTF8.self))
Detalles de la fuente

Entrada del catálogo

Id
identity/component-taxonomy/capabilities#knowledge
Repositorio
identity
Ruta
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82

Ejemplo

Id
identity/component-taxonomy/quickstart#knowledge
Repositorio
identity
Ruta
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82
Actualizado el 2026-10-10.