API keys

IT / Technical

API keys let an external system authenticate against Preb's public API. A key belongs to one workspace and acts on behalf of that workspace. Today, keys are used to record revenue through the transactions endpoint.

Creating a key

Only workspace admins and owners can create or manage keys.

Open API keys

In your workspace, go to Integrations → API keys (/w/{workspace}/integrations/api-keys).

Create a key

Click Create key and give it a name (1–120 characters). Names must be unique among your active keys, so pick something that identifies where it will be used — e.g. Zapier production.

Copy the secret

Preb shows the secret once. Copy it and store it in your secrets manager before closing the dialog (see below).

The one-time secret

A key has two parts:

  • A prefix like pk_a1B2c3D4 — a public identifier (pk_ followed by 8 characters). This is the only part Preb shows you again later.
  • A secret — a 40-character random string shown exactly once, at creation time.
prefix:  pk_a1B2c3D4
secret:  V1StGXR8_Z5jdHi6B-myT_pkb5tF2rN0c8Qm9aRk

The secret is shown only once

Preb stores the secret encrypted (it is never displayed again and never appears in any list or log). If you lose it, you can't recover it — revoke the key and create a new one. To stop you from closing the create dialog too early, it asks you to copy the secret and re-type the prefix before it lets you out.

Authentication

Preb does not use a plain bearer token. Instead, each request is signed: you compute an HMAC of the exact request body using your secret as the key, and send the prefix plus that signature.

The Authorization header format is:

Authorization: Bearer <prefix>:<hex(HMAC-SHA256(secret, rawBody))>

A worked example in Node.js:

import crypto from "node:crypto";

const prefix = "pk_a1B2c3D4";
const secret = "V1StGXR8_Z5jdHi6B-myT_pkb5tF2rN0c8Qm9aRk";

// Sign the EXACT bytes you send as the body.
const body = JSON.stringify({
  email: "buyer@example.com",
  amount: 4900,
  currency: "EUR",
  transaction_at: "2026-06-29T10:00:00Z",
});

const signature = crypto
  .createHmac("sha256", secret)
  .update(body, "utf8")
  .digest("hex");

await fetch("https://app.preb.co/api/public/transactions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${prefix}:${signature}`,
  },
  body,
});

Sign the raw body, byte-for-byte

The signature must cover the exact bytes you transmit. If a framework re-serialises your JSON (reordering keys or changing spacing) after you sign it, the signature won't match and you'll get 401 unauthorized. Build the body string once, sign that string, and send that string.

Every authentication failure — a missing or malformed header, an unknown or revoked prefix, or a wrong signature — returns the same opaque 401 unauthorized. There's no way to tell which part failed, by design.

Revoking a key

In Integrations → API keys, click Revoke next to a key. Revocation takes effect immediately and is idempotent — once revoked, the key can never authenticate again, and revoking it twice is harmless. Revoked keys drop off the list (only active keys are shown). If a key may be compromised, revoke it and issue a new one.

Audit log

Creating and revoking keys is recorded in your workspace audit trail as credential.api_key.created and credential.api_key.revoked. The entries capture the key's name and prefix and who made the change — never the secret, which is never written to any log.