Inovacc Desarrolladores

Guías

Autenticación

Toda llamada a una API de Inovacc se autentica con un solo encabezado, Authorization: Bearer <credential>. La credencial identifica a tu organización y, en el caso de la credencial de una aplicación, también a la aplicación, por lo que nunca las nombras en la solicitud. Las llamadas que cambian algo en la API de IA también llevan un X-Operation-Id, que las hace seguras de reintentar. Esta guía explica las credenciales, los encabezados que lee cada API, cómo funciona la idempotencia y cómo mantener las claves seguras durante toda su vida.

Los encabezados

EncabezadoDóndeValor
Authorizationtoda llamada, toda APIBearer <credential>
X-Operation-IdAPI de IA (ai.inovacc.dev): todo POST, PUT y DELETE; opcional en GETun id único que eliges: de 8 a 128 letras, dígitos, _ o -

Datos (data.inovacc.dev) y Eventos (events.inovacc.dev) no leen ningún encabezado de organización ni de operación: el tenant proviene solo de la credencial, y cualquier encabezado que intente nombrar a otro se ignora. Datos usa versiones HTTP (If-Match, If-None-Match) y Eventos usa un idempotency_key en el cuerpo para reintentos seguros; consulta sus páginas de producto.

Una solicitud sin credencial, con una mal formada o con una que no se reconoce se rechaza antes de que se ejecute nada: 401 con missing_credentials o invalid_credentials. En todas las API esta respuesta es la misma exista o no la ruta que llamaste, de modo que no se puede aprender nada de la API sin una credencial.

Obtén una clave

Las claves secretas las crea en la consola de Inovacc una persona de tu organización y se muestran una sola vez: Inovacc almacena solo un hash, por lo que una clave perdida no se puede mostrar de nuevo, solo reemplazar. Hoy el acceso es por invitación: pide a tu contacto de Inovacc que te invite, y luego crea una clave bajo tu organización.

Credenciales

CredencialAspectoParaAceptada por
Clave de API secretaaik_ seguido de 64 caracteres hexadecimalestus servidoresIA, Datos, Eventos
Token de acceso de cliente OAuthun token firmado emitido a un cliente de una aplicacióntus servidoresIA, Datos, Eventos
Clave publicableapb_...páginas web, desde los orígenes que su aplicación listaDatos (registros y archivos, donde las reglas lo permitan), Eventos (solo transmisiones)
Token de acceso de usuario finalemitido cuando una persona inicia sesión en tu aplicaciónel navegador o la app de esa personaDatos (registros y archivos, según las reglas de la colección)

Una clave puede estar vinculada a una aplicación. Una clave así alcanza solo lo que esa aplicación ha habilitado: en la API de IA cada ruta necesita una capacidad (ai.chat, ai.embeddings, knowledge, decision), y de lo contrario se rechaza con 403 capability_not_enabled; en Datos ve solo las bases de datos que creó su aplicación y la carpeta de archivos de su aplicación; en Eventos puede nombrar solo su propio espacio de trabajo.

Las claves publicables no son secretos. Están pensadas para incluirse dentro de una página web. Lo que protege tus datos es la lista de orígenes permitidos y, sobre todo, las reglas de cada colección: una clave publicable no puede hacer nada que una regla no admita.

Idempotencia

En la API de IA, X-Operation-Id es una clave de idempotencia. La primera respuesta exitosa a un id de operación se almacena durante 24 horas. Envía el mismo id de nuevo y recibes esa misma respuesta, marcada con x-idempotent-replay: true, sin que el trabajo se ejecute dos veces y sin un segundo cobro. Eso es lo que hace seguro un reintento tras un tiempo de espera agotado o una conexión interrumpida.

  • Un error nunca se almacena: reintentar una llamada fallida con el mismo id la ejecuta de nuevo.
  • Mientras la primera llamada sigue en ejecución, una segunda llamada con el mismo id es 409 operation_in_progress; espera y reintenta.
  • En chat, embeddings y run, un id reutilizado devuelve la respuesta almacenada sin importar lo que diga el cuerpo nuevo. En los elementos de colección, el mismo id con un archivo distinto es 409 operation_id_reused.
  • Genera un id nuevo para cada operación nueva, y reutiliza un id solo para reintentar la llamada para la que se creó.

Cada respuesta de IA repite el id con el que se ejecutó en x-operation-id; en un GET sin uno, el servicio inventa uno. Una respuesta de chat con streaming nunca se almacena, por lo que no se puede repetir.

Ejemplo

Lenguaje

⋮
    Línea de comandosEjemplo

    Shell

    export INOVACC_API_KEY="<your API key>"

    Lenguaje

    ⋮
    Solicitud en cURLEjemplo

    cURL

    curl "https://ai.inovacc.dev/v1/models" \
      -H "Authorization: Bearer $INOVACC_API_KEY"

    TypeScript

    const url = "https://ai.inovacc.dev/v1/models";
    
    const response = await fetch(url, {
      method: "GET",
      headers: {
        Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
      },
    });
    
    console.log(response.status, await response.text());

    Python

    import os
    import urllib.request
    
    request = urllib.request.Request(
        "https://ai.inovacc.dev/v1/models",
        method="GET",
        headers={
            "User-Agent": "inovacc-python-sample",
            "Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
        },
    )
    
    with urllib.request.urlopen(request) as response:
        print(response.status, response.read().decode())

    Go

    package main
    
    import (
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )
    
    const url = "https://ai.inovacc.dev/v1/models"
    
    func main() {
    	req, err := http.NewRequest("GET", url, nil)
    	if err != nil {
    		panic(err)
    	}
    	req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
    
    	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"] }
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let api_key = std::env::var("INOVACC_API_KEY")?;
        let response = reqwest::blocking::Client::new()
            .get("https://ai.inovacc.dev/v1/models")
            .bearer_auth(api_key)
            .send()?;
        println!("{} {}", response.status(), response.text()?);
        Ok(())
    }

    JavaScript

    const url = "https://ai.inovacc.dev/v1/models";
    
    const response = await fetch(url, {
      method: "GET",
      headers: {
        Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
      },
    });
    
    console.log(response.status, await response.text());

    PHP

    <?php
    
    $curl = curl_init('https://ai.inovacc.dev/v1/models');
    curl_setopt_array($curl, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
        ],
    ]);
    
    $response = curl_exec($curl);
    echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
    curl_close($curl);

    Ruby

    require "net/http"
    require "uri"
    
    uri = URI('https://ai.inovacc.dev/v1/models')
    
    request = Net::HTTP::Get.new(uri)
    request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
    
    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;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            String apiKey = System.getenv("INOVACC_API_KEY");
    
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://ai.inovacc.dev/v1/models"))
                    .header("Authorization", "Bearer " + apiKey)
                    .GET()
                    .build();
    
            HttpResponse<String> response = HttpClient.newHttpClient()
                    .send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.statusCode() + " " + response.body());
        }
    }

    C#

    var url = "https://ai.inovacc.dev/v1/models";
    var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");
    
    using var client = new HttpClient();
    using var request = new HttpRequestMessage(HttpMethod.Get, url);
    request.Headers.Add("Authorization", $"Bearer {apiKey}");
    
    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
    
    fun main() {
        val apiKey = System.getenv("INOVACC_API_KEY")
    
        val request = HttpRequest.newBuilder()
            .uri(URI.create("https://ai.inovacc.dev/v1/models"))
            .header("Authorization", "Bearer " + apiKey)
            .GET()
            .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 apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""
    
    let url = URL(string: "https://ai.inovacc.dev/v1/models")!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
    
    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))

    La respuesta lista las rutas configuradas para tu organización. Las rutas se nombran por organización, así que la lista que ves es la tuya. Una llamada que cambia algo agrega su id de operación:

    Lenguaje

    ⋮
      Línea de comandosEjemplo

      Shell

      curl -X POST "https://ai.inovacc.dev/v1/chat/completions" \
        -H "Authorization: Bearer $INOVACC_API_KEY" \
        -H "Content-Type: application/json" \
        -H "X-Operation-Id: $(uuidgen)" \
        -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}'

      Ciclo de vida de las claves

      Una clave pasa por cuatro etapas, y cada una tiene sus propios cuidados.

      1. Creación. Crea una clave por aplicación y por entorno (producción, staging, la laptop de un desarrollador), nunca una clave compartida por todo. Copia la clave directamente de la consola a tu almacén de secretos.
      2. Uso. Carga la clave desde el entorno o un administrador de secretos al arrancar. Envíala solo en el encabezado Authorization, solo por HTTPS, y solo desde un servidor: una clave secreta que llega a la API de Datos o de Eventos desde un navegador (con un encabezado Origin) se rechaza con 403 secret_key_in_browser.
      3. Rotación. Crea una segunda clave, despliégala en todos los lugares donde se usa la primera, confirma en el Registro de actividad que el id de la clave anterior ya no aparece como actor_id, y luego haz que se deshabilite la clave anterior. Una clave deshabilitada responde 403 key_disabled; revocar la credencial de una aplicación surte efecto en menos de un minuto.
      4. Retiro. Quita la clave de todo almacén de secretos y pipeline cuando una aplicación o un entorno desaparezca.

      Un comportamiento que conviene prever: en la Vector Database, el ámbito local pertenece a la clave que lo escribió. Una clave nueva ve un ámbito local nuevo y vacío; usa el ámbito shared para el conocimiento que debe sobrevivir a una rotación.

      Los tokens de acceso OAuth caducan. Cuando una llamada responde 401 invalid_credentials con un token que antes funcionaba, obtén un token nuevo y reintenta una vez; no reintentes un 401 en un bucle.

      Higiene de las claves

      • Nunca subas una clave al repositorio, ni siquiera a un repositorio privado o a un archivo de pruebas. Mantén los archivos .env fuera del control de versiones.
      • Nunca registres el encabezado Authorization, y ocúltalo en los reportes de errores y en las trazas.
      • Da a cada integración su propia clave, para que su tráfico sea visible en el Registro de actividad y pueda rotarse por separado.
      • Prefiere una clave vinculada a una aplicación con solo las capacidades que necesita en lugar de una clave para toda la organización.
      • Rota según un calendario, y de inmediato cuando se va alguien que tenía acceso o una clave pudo haberse filtrado.
      • En un navegador, usa una clave publicable o el token de una persona con sesión iniciada, y cierra toda colección con reglas.

      Ver también

      • Errores: el envoltorio de errores y los códigos que puedes manejar.
      • Límites: tamaños de solicitud, tiempos de espera y tasas.
      • Webhooks: verificar entregas con un secreto de firma.
      • Referencia de la API: cada producto y sus endpoints.
      Actualizado el 2026-10-10.