API d'integració v1

    Enllaços curts i secrets, des del codi

    Una sola clau bearer, JSON pla i les mateixes regles de pla que al tauler. Pensada per a extensions, CLI, servidors MCP i eines internes.

    Crea una clau d'APIEspecificació OpenAPI

    Accés anticipat. Els punts d'accés de la v1 s'activen espai de treball per espai de treball. Si una crida torna 503 amb el codi disabled, l'API encara no està activada per a vosaltres. Ja podeu crear claus, i funcionaran tan bon punt s'activi.

    Biblioteques de client

    Els secrets es xifren abans d'enviar-los, de manera que cada client ha de fer aquesta part pel seu compte. Aquestes biblioteques ho fan una sola vegada i correctament, contra els mateixos vectors de prova publicats al repositori que fa servir l'aplicació web. Totes tres tenen llicència MIT, es publiquen des de la CI amb procedència d'npm i només depenen de la biblioteca estàndard.

    SDK de TypeScript

    npm

    Client amb tipus per a cada ruta. Sense dependències, només WebCrypto, de manera que funciona sense canvis a Node 20+, Deno, Bun, navegadors i entorns d'execució perimetrals.

    npm i @uselinkpilot/sdk

    Línia d'ordres

    npm

    Passeu el secret per una canonada en lloc de passar-lo com a argument: un argument queda a l'historial de l'intèrpret d'ordres i es veu a la llista de processos.

    npm i -g linkpilot
    echo 'db password: hunter2' | linkpilot secret --ttl 1h

    Servidor MCP

    npm

    Permet que un assistent d'IA passi unes credencials a algú sense deixar-les en un registre de xat. Afegiu això a Claude Desktop, Claude Code, Cursor o qualsevol client MCP:

    {
      "mcpServers": {
        "linkpilot": {
          "command": "npx",
          "args": ["-y", "@uselinkpilot/mcp"],
          "env": { "LINKPILOT_API_KEY": "lp_live_..." }
        }
      }
    }

    Cal saber-ho abans d'instal·lar-lo: el text sense xifrar passa pel context de l'assistent, perquè el model ha de veure un secret per poder-lo crear. El servidor el protegeix en trànsit i en repòs, i fa que només s'obri una vegada. No el pot amagar del mateix model.

    Codi font: linkpilot-cli (SDK i CLI) i linkpilot-mcp.

    1. Autenticació

    Creeu una clau a /app/api-keys (propietaris i administradors de l'espai de treball). La clau completa es mostra una sola vegada; LinkPilot només en desa el hash SHA-256. Envieu-la a cada petició:

    Authorization: Bearer lp_live_...

    Les claus van lligades a un espai de treball, així que no hi ha cap paràmetre de client enlloc. Les claus revocades, caducades, desconegudes o mal formades tornen totes el mateix 401 unauthorized. Les claus no s'escriuen mai als registres.

    URL base: https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1

    2. Rutes

    MètodeCamíQuè fa
    GET/meEspai de treball, pla, límits, ús i el pressupost de peticions de la clau
    POST/linksCrea un enllaç curt (url, àlies opcional, domini, títol, etiquetes)
    GET/linksLlista els enllaços, primer els més nous, paginats amb cursor
    GET/links/{id}Obté un enllaç
    DELETE/links/{id}Suprimeix un enllaç
    POST/secretsCrea un enllaç secret (ciphertext, enc_version, ttl_seconds, burn_after_read, passphrase_hash al pla Pro)
    GET/secretsLlista les metadades dels secrets (mai el contingut)
    DELETE/secrets/{id}Revoca un secret i en destrueix el contingut
    POST/public/linksCrea un enllaç anònim amb un client_id, sense clau
    POST/public/secretsCrea un secret anònim que es destrueix després de la lectura, sense clau

    Les llistes tornen { data, next_cursor }; per continuar, torneu a enviar next_cursor com a cursor. limit va d'1 a 100.

    3. Exemples

    Crear un enllaç amb curl

    curl -X POST "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/links" \
      -H "Authorization: Bearer $LINKPILOT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"url":"https://example.com/launch","slug":"launch","tags":["campaign"]}'

    Crear un secret des de JavaScript

    const b64u = (b) => btoa(String.fromCharCode(...new Uint8Array(b)))
      .replace(/+/g, "-").replace(///g, "_").replace(/=+$/, "");
    
    // 1. Encrypt locally. This key is generated here and never sent anywhere.
    const key = crypto.getRandomValues(new Uint8Array(32));
    const iv = crypto.getRandomValues(new Uint8Array(12));
    const k = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]);
    const ct = await crypto.subtle.encrypt(
      { name: "AES-GCM", iv, tagLength: 128 },
      k,
      new TextEncoder().encode("staging db password"),
    );
    const ciphertext = `v1.${b64u(iv)}.${b64u(ct)}`;
    
    // 2. Store the blob. LinkPilot cannot read it.
    const res = await fetch("https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/secrets", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.LINKPILOT_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ ciphertext, enc_version: 1, ttl_seconds: 3600 }),
    });
    if (!res.ok) throw new Error((await res.json()).error.code);
    const { secret_url } = await res.json();
    
    // 3. Attach the key. Without this the link can never be opened, by anyone.
    const shareUrl = `${secret_url}#k=${b64u(key)}`;

    Llistar enllaços des de Python

    import os, requests
    
    r = requests.get(
        "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/links",
        params={"limit": 20},
        headers={"Authorization": f"Bearer {os.environ['LINKPILOT_API_KEY']}"},
    )
    r.raise_for_status()
    for link in r.json()["data"]:
        print(link["short_url"], "->", link["url"])
    print("remaining this hour:", r.headers["X-RateLimit-Remaining"])

    Crear un enllaç anònim sense clau

    curl -X POST "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/public/links" \
      -H "Content-Type: application/json" \
      -d '{"url":"https://example.com","client_id":"my-cli-0123456789abcdef"}'

    El contracte formal es publica aquí, no en un repositori: el document OpenAPI 3.1, la col·lecció de Postman i la referència escrita. Apunteu el generador de codi directament a l'URL d'OpenAPI.

    4. Com es desen els secrets

    Volem ser precisos, perquè aquí un client de l'API té feina de debò: l'API no accepta de cap manera un payload sense xifrar.

    • Vosaltres xifreu, nosaltres desem un blob. Envieu ciphertext (AES-GCM-256, v1.<iv>.<ct>) amb enc_version: 1. Si envieu payload, la petició es rebutja en lloc d'acceptar-se en silenci.
    • La clau l'heu d'afegir vosaltres. El secret_url que tornem no conté cap clau i no en pot contenir: no n'hem vist mai cap. Afegiu-hi #k=<base64url key>. Els navegadors no transmeten mai la part que va després del #, de manera que el destinatari desxifra el contingut al seu dispositiu.
    • No hi ha recuperació. Si perdeu la clau, el secret es perd, per a vosaltres i per a nosaltres. Així és com funciona la garantia.
    • Es destrueix en llegir-se, caducar o revocar-se. El text xifrat desat se sobreescriu al servidor.
    • L'API no el torna mai. Cap ruta no retorna un contingut ni un text xifrat. L'únic lector és la pàgina on el destinatari el mostra, que en registra la visualització.
    • Les frases de contrasenya (Pro i superiors) són un segon factor real: s'estiren amb PBKDF2-SHA256 i s'incorporen a la clau amb HKDF, de manera que ni l'enllaç sol ni la frase de contrasenya sola no desxifren res. Envieu només passphrase_hash, l'hexadecimal SHA-256 de la frase de contrasenya normalitzada en NFKC, i mai la frase de contrasenya en clar, que és la meitat de la clau. Deriveu la clau de la mateixa forma NFKC, perquè una frase de contrasenya escrita amb un altre teclat continuï obrint el secret.
    • Què no cobreix. Qui té l'enllaç complet té la clau, així que una caducitat curta i la destrucció després de la lectura continuen sent importants. Els fitxers adjunts es xifren de la mateixa manera, amb una clau derivada del mateix enllaç.

    El format de transmissió s'especifica a la referència de l'API, i @uselinkpilot/sdk fa tot l'intercanvi amb una sola crida si no el voleu implementar a mà. El mateix model es descriu a la pàgina d'arquitectura de seguretat.

    5. Límits del pla i límits de peticions

    LímitFreeProAgency
    Enllaços50Il·limitatsIl·limitats
    Secrets actius5100100
    Secrets amb frase de contrasenyaNoSíSí
    Dominis propis per als enllaçosDominis verificats existentsFins a 5Il·limitats
    Peticions per clau i hora601.0005.000

    L'API aplica les mateixes regles de pla que el tauler, llegides del mateix lloc, de manera que l'agrupació d'una agència també s'hi aplica. GET /me torna les xifres actuals del vostre espai de treball. Cada resposta autenticada inclou X-RateLimit-Limit, X-RateLimit-Remaining i X-RateLimit-Reset.

    Compara els plans

    6. Rutes públiques sense clau

    POST /public/links i POST /public/secrets existeixen per als clients que no poden mostrar una verificació al navegador: CLI, servidors MCP, el llançador. Reben un client_id opac (de 16 a 64 caràcters, generat una vegada per instal·lació) i creen registres al mateix conjunt anònim que les eines web gratuïtes.

    • 20 creacions per client i dia i 60 per xarxa i hora, a més dels límits per xarxa del mateix conjunt.
    • La mateixa comprovació amb fonts d'amenaces, la consulta d'URL amenaçadors de Google i les revisions programades que qualsevol altra via de creació.
    • Sense domini propi, sense àlies personalitzat i sense frase de contrasenya; els secrets públics sempre es destrueixen després d'una lectura i caduquen en un termini de 24 hores.
    • La resposta inclou un claim_token perquè un usuari que hagi iniciat la sessió pugui reclamar el registre per a un espai de treball més endavant. Tracteu-lo com una credencial.

    7. Errors

    Tots els errors tenen la forma { "error": { "code", "message", "upgrade_url"? } }. Els missatges indiquen el camp, mai les vostres dades. Els recursos d'altres espais de treball donen un 404, no un 403.

    CodiHTTPQuan
    unauthorized401Clau absent, mal formada, desconeguda, revocada o caducada
    disabled503L'API encara no està activada en aquesta instal·lació
    invalid_request400Error de validació, destinació bloquejada, àlies ja ocupat, domini desconegut
    not_found404La ruta no existeix o el recurs no és al vostre espai de treball
    plan_limit402S'ha arribat a la quota d'enllaços o de secrets actius (inclou upgrade_url)
    pro_required402Frase de contrasenya en un pla que no la inclou (inclou upgrade_url)
    rate_limited429S'ha esgotat el pressupost horari de la clau o la quota pública (inclou Retry-After)

    Preguntes dels desenvolupadors

    Quins plans inclouen l'API?
    Les claus d'API es creen des del tauler, a /app/api-keys. Cada clau fa servir els límits del pla del seu espai de treball: el pla Free té 50 enllaços i 5 secrets actius amb 60 peticions per hora; el pla Pro té enllaços il·limitats, 100 secrets actius, secrets protegits amb frase de contrasenya i 1.000 peticions per hora; els plans Agency tenen 5.000 peticions per hora.
    El contingut dels secrets té xifratge d'extrem a extrem?
    Sí, i l'API no accepta de cap manera text sense xifrar. Vosaltres xifreu amb AES-GCM-256 i envieu el text xifrat; LinkPilot desa un blob del qual no té la clau i que no pot desxifrar. Com que no veiem mai la clau, el secret_url que tornem no la conté: l'heu d'afegir vosaltres com a fragment #k=, que els navegadors no transmeten mai. Si perdeu la clau, ningú no pot recuperar el secret, ni tan sols nosaltres. Els fitxers adjunts es xifren de la mateixa manera, amb una clau derivada del mateix enllaç.
    Puc crear enllaços sense una clau d'API?
    Sí. POST /public/links i POST /public/secrets reben un client_id opac en lloc d'una clau i creen registres al mateix conjunt anònim que les eines web gratuïtes: 20 creacions per client i dia, 60 per xarxa i hora, sense domini propi, sense frase de contrasenya, i els secrets caduquen en un termini de 24 hores.
    Què passa quan arribo a un límit?
    Els límits del pla tornen HTTP 402 amb el codi plan_limit o pro_required i un upgrade_url. Els límits de peticions tornen 429 amb una capçalera Retry-After. Cada resposta autenticada inclou X-RateLimit-Limit, X-RateLimit-Remaining i X-RateLimit-Reset perquè els clients puguin reduir el ritme abans que passi.
    L'API és estable?
    Les rutes de la v1 no canviaran de manera incompatible. Els canvis incompatibles arriben amb una versió nova. Durant l'accés anticipat, els punts d'accés s'activen espai de treball per espai de treball; una resposta 503 amb el codi disabled vol dir que l'API encara no està activada per al vostre espai de treball.

    A punt per començar?

    Creeu una clau al vostre espai de treball o comenceu amb el pla Free.