Integrations-API v1

    Kortlinks og hemmeligheder direkte fra koden

    Én bearer-nøgle, almindelig JSON og de samme planregler som i dashboardet. Lavet til browserudvidelser, CLI'er, MCP-servere og interne værktøjer.

    Opret en API-nøgleOpenAPI-specifikation

    Tidlig adgang. Vi slår v1-endpoints til ét arbejdsområde ad gangen. Hvis et kald returnerer 503 med koden disabled, er API'et ikke slået til for dig endnu. Du kan oprette nøgler allerede i dag, og de virker, så snart det er.

    Klientbiblioteker

    Hemmeligheder krypteres, før de sendes, så hver klient skal selv klare den del. Disse biblioteker gør det én gang og korrekt, testet mod de samme testvektorer i repositoriet, som webappen bruger. Alle tre er MIT-licenserede, udgives fra CI med npm provenance og afhænger kun af standardbiblioteket.

    TypeScript-SDK

    npm

    Typet klient til alle ruter. Ingen afhængigheder, kun WebCrypto, så den kører uændret på Node 20+, Deno, Bun, browsere og edge-runtimes.

    npm i @uselinkpilot/sdk

    Kommandolinje

    npm

    Send hemmeligheden ind via en pipe i stedet for som argument: et argument havner i din shell-historik og kan ses i proceslisten.

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

    MCP-server

    npm

    Lader en AI-assistent give nogen loginoplysninger uden at lægge dem i en chatlog. Tilføj dette til Claude Desktop, Claude Code, Cursor eller en anden MCP-klient:

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

    Godt at vide, før du installerer den: klarteksten passerer gennem assistentens kontekst, fordi modellen skal se en hemmelighed for at kunne oprette den. Serveren beskytter hemmeligheden under overførsel og i lagring, og linket kan kun åbnes én gang. Hemmeligheden kan ikke skjules for selve modellen.

    Kildekode: linkpilot-cli (SDK og CLI) og linkpilot-mcp.

    1. Autentificering

    Opret en nøgle på /app/api-keys (ejere og administratorer af arbejdsområdet). Den rå nøgle vises kun én gang, og LinkPilot gemmer kun dens SHA-256-hash. Send den med hver forespørgsel:

    Authorization: Bearer lp_live_...

    Nøgler er knyttet til et arbejdsområde, så der er ingen tenant-parameter nogen steder. Tilbagekaldte, udløbne, ukendte og forkert formaterede nøgler returnerer alle det samme 401 unauthorized. Nøgler skrives aldrig i logfiler.

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

    2. Ruter

    MetodeStiHvad den gør
    GET/meArbejdsområde, plan, grænser, forbrug og din nøgles forespørgselskvote
    POST/linksOpret et kortlink (URL samt valgfri slug, domæne, titel og tags)
    GET/linksVis links, nyeste først, med cursor-paginering
    GET/links/{id}Hent ét link
    DELETE/links/{id}Slet et link
    POST/secretsOpret et hemmeligt link (ciphertext, enc_version, ttl_seconds, burn_after_read og passphrase_hash på Pro)
    GET/secretsVis metadata for hemmeligheder (aldrig indholdet)
    DELETE/secrets/{id}Tilbagekald en hemmelighed, og destruer indholdet
    POST/public/linksOpret et anonymt link med et client_id, uden nøgle
    POST/public/secretsOpret en anonym hemmelighed, der slettes efter læsning, uden nøgle

    Lister returnerer { data, next_cursor }. Send next_cursor tilbage som cursor for at hente flere. limit er 1 til 100.

    3. Eksempler

    Opret et link med 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"]}'

    Opret en hemmelighed fra 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)}`;

    Vis links fra 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"])

    Opret et anonymt link uden nøgle

    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"}'

    Den formelle kontrakt udgives her og ikke i et repository: OpenAPI 3.1-dokumentet, Postman-samlingen og den skrevne reference. Peg din kodegenerator direkte på OpenAPI-URL'en.

    4. Sådan gemmes hemmeligheder

    Vi vil gerne være præcise her, fordi en API-klient selv har reelt arbejde at gøre: API'et accepterer slet ikke et payload i klartekst.

    • Du krypterer, vi gemmer en blob. Send ciphertext (AES-GCM-256, v1.<iv>.<ct>) med enc_version: 1. Sender du payload, bliver kaldet afvist i stedet for at blive accepteret i stilhed.
    • Du skal selv tilføje nøglen. Den secret_url, vi returnerer, indeholder ingen nøgle og kan heller ikke gøre det: vi har aldrig set nøglen. Tilføj #k=<base64url key>. Browsere sender aldrig den del af linket, der står efter #, så modtageren dekrypterer lokalt.
    • Der er ingen gendannelse. Mister du nøglen, er hemmeligheden væk, både for dig og for os. Sådan virker garantien.
    • Destrueres ved læsning, udløb eller tilbagekaldelse. Den gemte chiffertekst overskrives på serveren.
    • API'et returnerer den aldrig. Ingen rute sender indhold eller chiffertekst tilbage. Det eneste, der læser den, er modtagerens visningsside, og den registrerer visningen.
    • Adgangssætninger (Pro og højere) er en reel anden faktor: de strækkes med PBKDF2-SHA256 og indregnes i nøglen med HKDF, så hverken linket eller adgangssætningen alene kan dekryptere. Send kun passphrase_hash, dvs. SHA-256-hex af den NFKC-normaliserede adgangssætning. Send aldrig selve adgangssætningen, for den er halvdelen af nøglen. Afled nøglen af den samme NFKC-form, så en adgangssætning, der er skrevet på et andet tastatur, stadig åbner hemmeligheden.
    • Hvad det ikke dækker. Den, der har hele linket, har også nøglen, så kort udløbstid og sletning efter læsning er stadig vigtige. Vedhæftede filer krypteres på samme måde med en nøgle, der er afledt af det samme link.

    Dataformatet er beskrevet i API-referencen, og @uselinkpilot/sdk klarer hele udvekslingen i ét kald, hvis du hellere vil slippe for at skrive det selv. Samme model er beskrevet på siden om sikkerhedsarkitektur.

    5. Plangrænser og forespørgselsgrænser

    GrænseFreeProAgency
    Links50UbegrænsetUbegrænset
    Aktive hemmeligheder5100100
    Hemmeligheder med adgangssætningNejJaJa
    Egne domæner til linksEksisterende verificerede domænerOp til 5Ubegrænset
    Forespørgsler pr. nøgle pr. time601.0005.000

    API'et bruger de samme planregler som dashboardet og henter dem samme sted fra, så et bureaus samlede grænser på tværs af arbejdsområder gælder også her. GET /me returnerer de aktuelle tal for dit arbejdsområde. Alle autentificerede svar indeholder X-RateLimit-Limit, X-RateLimit-Remaining og X-RateLimit-Reset.

    Sammenlign planer

    6. Offentlige ruter uden nøgle

    POST /public/links og POST /public/secrets findes til klienter, der ikke kan vise en browserudfordring: CLI'er, MCP-servere og launcheren. De tager et opakt client_id (16 til 64 tegn, genereres én gang pr. installation) og opretter poster i den samme anonyme pulje som de gratis webværktøjer.

    • 20 oprettelser pr. klient pr. dag og 60 pr. netværk pr. time, plus puljens egne grænser pr. netværk.
    • Den samme screening som alle andre måder at oprette på: trusselsfeeds, Googles opslag af farlige URL'er og planlagte genkontroller.
    • Intet eget domæne, ingen egen slug og ingen adgangssætning. Offentlige hemmeligheder slettes altid efter én læsning og udløber inden for 24 timer.
    • Svaret indeholder et claim_token, så en bruger, der er logget ind, senere kan knytte posten til et arbejdsområde. Behandl det som loginoplysninger.

    7. Fejl

    Alle fejl har formen { "error": { "code", "message", "upgrade_url"? } }. Meddelelserne nævner feltet, aldrig dine data. Ressourcer i andre arbejdsområder giver 404, ikke 403.

    KodeHTTPHvornår
    unauthorized401Manglende, forkert formateret, ukendt, tilbagekaldt eller udløbet nøgle
    disabled503API'et er endnu ikke slået til for denne installation
    invalid_request400Valideringsfejl, blokeret destination, en slug, der allerede er i brug, eller et ukendt domæne
    not_found404Ruten findes ikke, eller ressourcen er ikke i dit arbejdsområde
    plan_limit402Kvoten for links eller aktive hemmeligheder er nået (upgrade_url medfølger)
    pro_required402Adgangssætning på en plan, der ikke har den (upgrade_url medfølger)
    rate_limited429Nøglens timekvote eller den offentlige kvote er brugt op (Retry-After medfølger)

    Spørgsmål fra udviklere

    Hvilke planer giver adgang til API'et?
    API-nøgler oprettes fra dashboardet på /app/api-keys. Hver nøgle følger plangrænserne for sit arbejdsområde: Free har 50 links og 5 aktive hemmeligheder med 60 forespørgsler i timen. Pro har ubegrænsede links, 100 aktive hemmeligheder, hemmeligheder beskyttet med adgangssætning og 1.000 forespørgsler i timen. Agency-planerne får 5.000 forespørgsler i timen.
    Er indholdet af hemmeligheder end-to-end-krypteret?
    Ja, og API'et accepterer slet ikke klartekst. Du krypterer med AES-GCM-256 og sender chiffertekst. LinkPilot gemmer en blob, som vi ikke har nøglen til og ikke kan dekryptere. Da vi aldrig ser din nøgle, indeholder den secret_url, vi returnerer, ingen nøgle. Du tilføjer den selv som et #k=-fragment, og den del sender browsere aldrig. Mister du nøglen, kan ingen gendanne hemmeligheden, heller ikke vi. Vedhæftede filer krypteres på samme måde med en nøgle, der er afledt af det samme link.
    Kan jeg oprette links uden en API-nøgle?
    Ja. POST /public/links og POST /public/secrets tager et opakt client_id i stedet for en nøgle og opretter poster i den samme anonyme pulje som de gratis webværktøjer: 20 oprettelser pr. klient pr. dag, 60 pr. netværk pr. time, intet eget domæne og ingen adgangssætning. Hemmeligheder udløber inden for 24 timer.
    Hvad sker der, når jeg rammer en grænse?
    Plangrænser returnerer HTTP 402 med koden plan_limit eller pro_required og en upgrade_url. Forespørgselsgrænser returnerer 429 med en Retry-After-header. Alle autentificerede svar indeholder X-RateLimit-Limit, X-RateLimit-Remaining og X-RateLimit-Reset, så klienter kan sætte tempoet ned, før det sker.
    Er API'et stabilt?
    v1-ruterne ændres ikke på en måde, der bryder eksisterende integrationer. Den slags ændringer kommer i en ny version. I perioden med tidlig adgang slås endpoints til ét arbejdsområde ad gangen. Et 503-svar med koden disabled betyder, at API'et endnu ikke er slået til for dit arbejdsområde.

    Klar til at bygge?

    Opret en nøgle i dit arbejdsområde, eller start med Free-planen.