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.
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
npmClient 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/sdkLínia d'ordres
npmPasseu 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 1hServidor MCP
npmPermet 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ètode | Camí | Què fa |
|---|---|---|
| GET | /me | Espai de treball, pla, límits, ús i el pressupost de peticions de la clau |
| POST | /links | Crea un enllaç curt (url, àlies opcional, domini, títol, etiquetes) |
| GET | /links | Llista els enllaços, primer els més nous, paginats amb cursor |
| GET | /links/{id} | Obté un enllaç |
| DELETE | /links/{id} | Suprimeix un enllaç |
| POST | /secrets | Crea un enllaç secret (ciphertext, enc_version, ttl_seconds, burn_after_read, passphrase_hash al pla Pro) |
| GET | /secrets | Llista les metadades dels secrets (mai el contingut) |
| DELETE | /secrets/{id} | Revoca un secret i en destrueix el contingut |
| POST | /public/links | Crea un enllaç anònim amb un client_id, sense clau |
| POST | /public/secrets | Crea 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>) ambenc_version: 1. Si envieupayload, la petició es rebutja en lloc d'acceptar-se en silenci. - La clau l'heu d'afegir vosaltres. El
secret_urlque 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ímit | Free | Pro | Agency |
|---|---|---|---|
| Enllaços | 50 | Il·limitats | Il·limitats |
| Secrets actius | 5 | 100 | 100 |
| Secrets amb frase de contrasenya | No | Sí | Sí |
| Dominis propis per als enllaços | Dominis verificats existents | Fins a 5 | Il·limitats |
| Peticions per clau i hora | 60 | 1.000 | 5.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.
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_tokenperquè 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.
| Codi | HTTP | Quan |
|---|---|---|
| unauthorized | 401 | Clau absent, mal formada, desconeguda, revocada o caducada |
| disabled | 503 | L'API encara no està activada en aquesta instal·lació |
| invalid_request | 400 | Error de validació, destinació bloquejada, àlies ja ocupat, domini desconegut |
| not_found | 404 | La ruta no existeix o el recurs no és al vostre espai de treball |
| plan_limit | 402 | S'ha arribat a la quota d'enllaços o de secrets actius (inclou upgrade_url) |
| pro_required | 402 | Frase de contrasenya en un pla que no la inclou (inclou upgrade_url) |
| rate_limited | 429 | S'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.