Integrations and Technology

API Security Basics: Keys, Scopes and Signed Links

How API keys, scopes, signed webhooks and signed links protect business data, and the everyday habits that stop a leaked key from becoming a data breach.

Illustrative example with fictional data.

When you connect systems through an API, you're handing a piece of software the ability to act on your business data. Four mechanisms decide how much damage a mistake can do: the key, its scopes, signed webhooks and signed links. This guide explains each in plain terms, with the habits that matter more than any of them.

1. API keys: a password for software

An API key identifies the system making a request, the way a password identifies a person. Every request carries it in a header:

Authorization: ApiKey flx_live_…

Three properties make a key safer:

  • It's shown once. A well-designed system stores only a scrambled version (a hash), so even its own staff can't read your key back. In Flux, keys start with flx_live_, the full key is displayed once at creation, and a lost key can't be recovered: you create a new one and revoke the old.
  • It can be revoked instantly. A revoked Flux key stops working at once.
  • It belongs to one organisation. A Flux key can't see another organisation's data, even in the same group.

The habit that matters: treat a key like cash. Keep it in your server's secret settings, never in website code a browser downloads, never in a shared spreadsheet, and never pasted into a chat.

2. Scopes: give each system only what it needs

A scope is a permission attached to a key. The principle is the same one finance teams already use for people: least privilege. The clerk who raises vouchers doesn't need to approve them.

Flux has seven scopes:

Scope What it allows
customers:read Read customers, their enrolments and statements
customers:write Create and update customers
invoices:read Read invoices and receipts, and create signed links
invoices:write Raise invoices
payments:read Read payment attempts
payments:write Start a checkout
webhooks:manage Manage webhook endpoints and deliveries

Here is how a school in Lekki might split its keys:

System Scopes Why
Parent portal invoices:read Shows invoices and payment links; can't create anything
Admissions system customers:write, invoices:write Creates new families and their first term's invoice
Operations server webhooks:manage Registers the endpoint that receives payment events

If the parent portal's key leaks, the worst outcome is that someone can read invoices. They can't raise one, change a customer, or redirect webhooks. That's the whole point of scopes: a leak is contained to what that one system could do.

3. Signed webhooks: proving a message is genuine

A webhook arrives at a public web address, so your system needs to know it really came from your finance system and wasn't forged or altered on the way.

The answer is a signature. When you register a webhook endpoint, you and the sender share a secret. Each delivery carries a signature computed from that secret, a timestamp and the exact message body. In Flux, it's the Flux-Signature header, t=<timestamp>,v1=<HMAC-SHA256>, computed over the timestamp, a dot, and the raw body.

Your code recomputes the signature and compares. Two details make the difference between a check and a real check:

  • Compare against the raw body. If your framework parses and re-formats the JSON first, the signature won't match, and developers under pressure "fix" this by skipping the check.
  • Check the timestamp too. A signature proves who sent a message, not when. Rejecting messages more than a few minutes old (Flux's examples use five) stops an attacker who captured a genuine "invoice paid" from replaying it later.

Our webhooks guide covers the rest of a safe receiver.

Customers need to open invoice PDFs and pay without creating an account. A signed link solves this: a URL with a tamper-proof signature in it, which works only for that document and only until it expires.

In Flux, signed PDF and payment links last 30 days by default. Two habits keep them safe:

  • Fetch them fresh when you show them, for example when the customer's billing page loads, instead of storing them in your database.
  • Show a link only to the customer it belongs to, and only over HTTPS. Anyone who has a signed link can use it until it expires.

A short security checklist

  • One key per connected system, with only the scopes it needs.
  • Keys live in server-side secret storage, never in browser code or documents.
  • Every key has a named owner, and leavers' keys are revoked the day they leave.
  • Webhook signatures and timestamps are verified on every delivery.
  • Signed links are generated when shown and sent only to their owner.
  • Someone reviews the list of active keys every quarter and revokes what's unused.

How Flux helps

In Flux, organisation admins create and revoke API keys, choosing scopes per key. Every webhook is signed, and PDF and payment links are signed and expire. Invoices raised through the API still go through your approval workflow, so a compromised integration can't send an invoice nobody approved. The Developers page summarises the security model; developers.flux-erp.app has the full details, including signature-verification code you can copy.

From the blog