Lyhytlinkit ja salaisuudet suoraan koodista
Yksi bearer-avain, tavallista JSONia ja samat pakettisäännöt kuin hallintapaneelissa. Tehty selainlaajennuksille, CLI-työkaluille, MCP-palvelimille ja sisäisille työkaluille.
Ennakkokäyttö. Otamme v1-päätepisteet käyttöön työtila kerrallaan. Jos kutsu palauttaa tilakoodin 503 ja koodin disabled, API ei ole vielä käytössäsi. Avaimia voi luoda jo nyt, ja ne toimivat heti, kun API otetaan käyttöön.
Asiakaskirjastot
Salaisuudet salataan ennen lähettämistä, joten jokaisen asiakasohjelman on tehtävä se itse. Nämä kirjastot tekevät sen kerran ja oikein, ja ne testataan samoilla versionhallintaan tallennetuilla testivektoreilla kuin verkkosovellus. Kaikilla kolmella on MIT-lisenssi, ne julkaistaan CI-putkesta npm:n alkuperätiedoin (provenance), eivätkä ne riipu mistään muusta kuin standardikirjastosta.
TypeScript-SDK
npmTyypitetty asiakasohjelma jokaiselle reitille. Ei riippuvuuksia, vain WebCrypto, joten se toimii muuttamatta näissä: Node 20+, Deno, Bun, selaimet ja edge-ajoympäristöt.
npm i @uselinkpilot/sdkKomentorivi
npmOhjaa salaisuus komennolle putkella äläkä anna sitä argumenttina: argumentti jää komentotulkin historiaan ja näkyy prosessiluettelossa.
npm i -g linkpilot
echo 'db password: hunter2' | linkpilot secret --ttl 1hMCP-palvelin
npmTekoälyavustaja voi antaa jollekulle kirjautumistiedot ilman, että ne jäävät keskusteluhistoriaan. Lisää tämä Claude Desktopiin, Claude Codeen, Cursoriin tai mihin tahansa MCP-asiakasohjelmaan:
{
"mcpServers": {
"linkpilot": {
"command": "npx",
"args": ["-y", "@uselinkpilot/mcp"],
"env": { "LINKPILOT_API_KEY": "lp_live_..." }
}
}
}Ennen asennusta on hyvä tietää: selväkielinen sisältö kulkee avustajan kontekstin läpi, koska mallin on nähtävä salaisuus voidakseen luoda sen. Tämä suojaa salaisuutta siirron aikana ja tallennettuna, ja linkin voi avata vain kerran. Itse mallilta sitä ei voi piilottaa.
Lähdekoodi: linkpilot-cli (SDK ja CLI) ja linkpilot-mcp.
1. Tunnistautuminen
Luo avain sivulla /app/api-keys (työtilan omistajat ja ylläpitäjät). Avain näytetään kokonaisena vain kerran, ja LinkPilot säilyttää siitä vain SHA-256-tiivisteen. Lähetä avain jokaisen pyynnön mukana:
Authorization: Bearer lp_live_...Avaimet on sidottu työtilaan, joten tenant-parametria ei ole missään. Mitätöidystä, vanhentuneesta, tuntemattomasta ja väärämuotoisesta avaimesta palautuu sama vastaus 401 unauthorized. Avaimia ei koskaan kirjoiteta lokeihin.
Perusosoite: https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1
2. Reitit
| Metodi | Polku | Mitä se tekee |
|---|---|---|
| GET | /me | Työtila, paketti, rajat, käyttö ja avaimesi pyyntökiintiö |
| POST | /links | Luo lyhytlinkki (kentät url, valinnainen slug, domain, title, tags) |
| GET | /links | Listaa linkit uusimmasta alkaen, kursoripohjainen sivutus |
| GET | /links/{id} | Hae yksi linkki |
| DELETE | /links/{id} | Poista linkki |
| POST | /secrets | Luo salainen linkki (ciphertext, enc_version, ttl_seconds, burn_after_read, Pro-paketissa passphrase_hash) |
| GET | /secrets | Listaa salaisuuksien metatiedot (ei koskaan sisältöä) |
| DELETE | /secrets/{id} | Mitätöi salaisuus ja tuhoa sen sisältö |
| POST | /public/links | Luo nimetön linkki client_id-tunnisteella ilman avainta |
| POST | /public/secrets | Luo nimetön, lukemisen jälkeen tuhoutuva salaisuus ilman avainta |
Listat palauttavat muodon { data, next_cursor }. Jatka antamalla next_cursor takaisin parametrina cursor. Parametrin limit arvo on 1–100.
3. Esimerkit
Luo linkki curlilla
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"]}'Luo salaisuus JavaScriptillä
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)}`;Listaa linkit Pythonilla
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"])Luo nimetön linkki ilman avainta
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"}'Rajapinnan virallinen kuvaus julkaistaan täällä eikä koodivarastossa: OpenAPI 3.1 -dokumentti, Postman-kokoelma ja kirjallinen viiteopas. Osoita koodigeneraattorisi suoraan OpenAPI-kuvauksen URL-osoitteeseen.
4. Miten salaisuudet tallennetaan
Haluamme olla tarkkoja, koska API-asiakasohjelman on tässä tehtävä oikeaa työtä: API ei hyväksy selväkielistä kenttää payload lainkaan.
- Sinä salaat, me tallennamme salatun tavujonon. Lähetä kenttä
ciphertext(AES-GCM-256,v1.<iv>.<ct>) ja sen mukanaenc_version: 1. Jos lähetät kentänpayload, pyyntö hylätään eikä sitä hyväksytä hiljaa. - Avain on lisättävä itse. Palauttamamme
secret_urlei sisällä avainta eikä voisikaan: emme ole koskaan nähneet sitä. Lisää loppuun#k=<base64url key>. Selaimet eivät koskaan lähetä merkin#jälkeistä osaa, joten vastaanottaja purkaa salauksen omalla laitteellaan. - Palautusta ei ole. Jos avain katoaa, salaisuus on menetetty sekä sinulta että meiltä. Juuri tämä osoittaa, että takuu toimii.
- Tuhotaan, kun salaisuus avataan, vanhenee tai mitätöidään. Tallennettu salateksti ylikirjoitetaan palvelimella.
- API ei koskaan palauta sitä. Mikään reitti ei palauta sisältöä eikä salatekstiä. Sen lukee vain vastaanottajan avaussivu, joka kirjaa avauksen.
- Salalauseet (Pro-paketista ylöspäin) ovat todellinen toinen tekijä: ne venytetään PBKDF2-SHA256:lla ja yhdistetään avaimeen HKDF:llä, joten salausta ei voi purkaa pelkällä linkillä eikä pelkällä salalauseella. Lähetä vain
passphrase_hasheli NFKC-normalisoidun salalauseen SHA-256-tiiviste heksamuodossa. Älä koskaan lähetä salalausetta sellaisenaan, koska se on puolet avaimesta. Johda avain samasta NFKC-muodosta, jotta salaisuus aukeaa myös toisella näppäimistöllä kirjoitetulla salalauseella. - Mitä tämä ei kata. Koko linkin haltijalla on myös avain, joten lyhyt voimassaoloaika ja tuhoutuminen lukemisen jälkeen ovat edelleen tärkeitä. Liitetiedostot salataan samalla tavalla avaimella, joka johdetaan samasta linkistä.
Siirtomuoto on kuvattu API-viitteessä, ja kirjasto @uselinkpilot/sdk hoitaa koko vaihdon yhdellä kutsulla, jos et halua toteuttaa sitä itse. Samaa mallia kuvataan tietoturva-arkkitehtuurisivulla.
5. Pakettien rajat ja pyyntörajat
| Raja | Free | Pro | Agency |
|---|---|---|---|
| Linkit | 50 | Rajattomasti | Rajattomasti |
| Aktiiviset salaisuudet | 5 | 100 | 100 |
| Salalauseella suojatut salaisuudet | Ei | Kyllä | Kyllä |
| Omat verkkotunnukset linkeille | Jo vahvistetut verkkotunnukset | Enintään 5 | Rajattomasti |
| Pyynnöt tunnissa avainta kohden | 60 | 1 000 | 5 000 |
API noudattaa samoja pakettisääntöjä kuin hallintapaneeli ja lukee ne samasta paikasta, joten myös toimiston asiakastyötilojen yhteenlasketut rajat pätevät tässä. Kutsu GET /me palauttaa työtilasi ajantasaiset luvut. Jokaisessa tunnistautuneen pyynnön vastauksessa on otsakkeet X-RateLimit-Limit, X-RateLimit-Remaining ja X-RateLimit-Reset.
6. Julkiset reitit ilman avainta
Reitit POST /public/links ja POST /public/secrets ovat asiakasohjelmille, jotka eivät pysty näyttämään selaimessa tehtävää tarkistusta: CLI-työkaluille, MCP-palvelimille ja käynnistimelle. Ne ottavat vastaan läpinäkymättömän tunnisteen client_id (16–64 merkkiä, luodaan kerran asennusta kohden) ja luovat tietueita samaan nimettömään varantoon kuin ilmaiset verkkotyökalut.
- 20 luontia asiakasohjelmaa kohden päivässä ja 60 verkkoa kohden tunnissa, minkä lisäksi varannolla on omat verkkokohtaiset rajansa.
- Sama uhkasyötteiden seulonta, Googlen URL-uhkatarkistus ja ajastetut uusintatarkistukset kuin kaikilla muillakin luontitavoilla.
- Ei omaa verkkotunnusta, omaa polkutunnusta eikä salalausetta. Julkiset salaisuudet tuhoutuvat aina yhden lukemisen jälkeen ja vanhenevat 24 tunnin kuluessa.
- Vastauksessa on liittämistunniste
claim_token, jolla kirjautunut käyttäjä voi myöhemmin liittää tietueen työtilaan. Käsittele sitä kuin kirjautumistietoja.
7. Virheet
Jokainen virhe on muotoa { "error": { "code", "message", "upgrade_url"? } }. Viestit nimeävät kentän, eivät koskaan tietojasi. Muiden työtilojen resursseista palautuu 404 eikä 403.
| Koodi | HTTP | Milloin |
|---|---|---|
| unauthorized | 401 | Avain puuttuu tai on väärämuotoinen, tuntematon, mitätöity tai vanhentunut |
| disabled | 503 | API ei ole vielä käytössä tässä ympäristössä |
| invalid_request | 400 | Validointivirhe, estetty kohde, varattu polkutunnus tai tuntematon verkkotunnus |
| not_found | 404 | Reittiä ei ole tai resurssi ei ole työtilassasi |
| plan_limit | 402 | Linkkien tai aktiivisten salaisuuksien kiintiö on täynnä (mukana upgrade_url) |
| pro_required | 402 | Salalause paketissa, johon se ei sisälly (mukana upgrade_url) |
| rate_limited | 429 | Avaimen tuntikiintiö tai julkinen kiintiö on käytetty (mukana Retry-After) |
Kehittäjien kysymyksiä
- Mihin paketteihin API sisältyy?
- API-avaimet luodaan hallintapaneelissa osoitteessa /app/api-keys. Jokainen avain noudattaa oman työtilansa paketin rajoja. Free-paketissa on 50 linkkiä, 5 aktiivista salaisuutta ja 60 pyyntöä tunnissa. Pro-paketissa on rajattomasti linkkejä, 100 aktiivista salaisuutta, salalauseella suojatut salaisuudet ja 1 000 pyyntöä tunnissa. Agency-paketeissa on 5 000 pyyntöä tunnissa.
- Onko salaisuuksien sisältö salattu päästä päähän?
- On, eikä API hyväksy selväkielistä sisältöä lainkaan. Salaat sisällön AES-GCM-256:lla ja lähetät salatekstin. LinkPilot tallentaa salatun tavujonon, johon sillä ei ole avainta, eikä se pysty purkamaan sitä. Koska emme koskaan näe avaintasi, palauttamassamme secret_url-osoitteessa ei ole avainta. Lisäät sen itse linkin #-merkin jälkeiseen osaan muodossa #k=, eivätkä selaimet koskaan lähetä tätä osaa. Jos avain katoaa, kukaan ei voi palauttaa salaisuutta, emme mekään. Liitetiedostot salataan samalla tavalla avaimella, joka johdetaan samasta linkistä.
- Voiko linkkejä luoda ilman API-avainta?
- Voi. Reitit POST /public/links ja POST /public/secrets ottavat avaimen sijaan vastaan läpinäkymättömän client_id-tunnisteen ja luovat tietueita samaan nimettömään varantoon kuin ilmaiset verkkotyökalut: 20 luontia asiakasohjelmaa kohden päivässä, 60 verkkoa kohden tunnissa, ei omaa verkkotunnusta, ei salalausetta, ja salaisuudet vanhenevat 24 tunnin kuluessa.
- Mitä tapahtuu, kun raja tulee vastaan?
- Pakettirajan ylittyessä palautuu HTTP 402 -vastaus, jossa on koodi plan_limit tai pro_required sekä upgrade_url. Pyyntörajan ylittyessä palautuu vastaus 429 ja otsake Retry-After. Jokaisessa tunnistautuneen pyynnön vastauksessa on otsakkeet X-RateLimit-Limit, X-RateLimit-Remaining ja X-RateLimit-Reset, joten asiakasohjelma voi hidastaa tahtia ennen kuin raja tulee vastaan.
- Onko API vakaa?
- Version v1 reitteihin ei tehdä yhteensopivuutta rikkovia muutoksia. Rikkovat muutokset julkaistaan uutena versiona. Ennakkokäytön aikana päätepisteet otetaan käyttöön työtila kerrallaan. Vastaus 503 koodilla disabled tarkoittaa, että API ei ole vielä käytössä työtilassasi.
Haluatko aloittaa?
Luo avain työtilassasi tai aloita Free-paketilla.