Slate API Keys and Webhooks: Setup Guide
Create a Read only key and a Full access key, turn on webhooks, add an endpoint, verify its signature and test it in sandbox. Then repeat the same steps in live.
Read
8 min read
Published On
Oct 29, 2026
Read: 8 minutes
Last updated: November 10, 2026
In this guide
- Full access keys read and write. Read only keys can only read, and writes are refused with a 403
- A key is shown once, so store it before you close the dialog
- Webhooks are one switch, then an embedded portal where you add endpoints and choose events
- Sandbox and live are separate. Set up both
Two Kinds of Key, and Who Should Hold Each
Open Developers in the sidebar, then API keys. The page is titled "Create and manage keys for the Slate API". Choose "Create API Key" and pick one of two access levels.
| Access | What it can do | Who should hold it |
|---|---|---|
| Full access | Read and write. Create customers, attach data, create requests | Your backend servers, and nobody else |
| Read only | GET requests only. Any write is refused with a 403 | Analytics, dashboards, support tools and anything that only needs to look |
The reason to have both is blast radius. A reporting job does not need the power to create customers. If its key ends up in a log file or a shared spreadsheet, a Read only key can leak data but cannot change anything.
Create Your First Keys
- Check which dashboard you are in. Sandbox shows a banner at the top, and keys made there only work in sandbox.
- Go to Developers, then API keys, and choose "Create API Key".
- Pick "Full access" or "Read only".
- Copy the key from the "API Key Created" dialog and put it in your secrets manager straight away. The dialog shows it once.
- Check the new row. It lists the key as a prefix, dots and the last four characters, with an Access badge and a Created date.
There is no way to see a key again. If you lose it, create a new key and revoke the old one. The page has no key naming, expiry or rotation settings, so keep your own record of which key is used where: system, access level and who created it.
You can also create a key from the Home checklist in sandbox, in the step called "Create an API key". It produces the same kind of key.
Make a Call With Each Key
Slate reads the key from the x-api-key header. The live API is at https://api.tryslatehq.com and the sandbox API is at https://api-sandbox.tryslatehq.com. Every list page has an "API reference" button with snippets for that page's operations. Copy the path and body from there, and send the key in x-api-key. The full reference is at tryslatehq.apidocumentation.com/slate-api.
A good first test proves the access levels do what they say. List customers with the Read only key and expect a normal answer. Then try to create a customer with the same key and expect a 403. With the Full access key, the same create call should succeed.
# 1) Read with the Read only key: expect 200
curl -s -o /dev/null -w "%{http_code}\n" \
-H "x-api-key: $SLATE_READ_KEY" \
https://api-sandbox.tryslatehq.com/customers
# 2) Write with the same key: expect 403
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
-H "x-api-key: $SLATE_READ_KEY" \
-H "Content-Type: application/json" \
-d '<body from the Create a customer sheet>' \
https://api-sandbox.tryslatehq.com/customers
Run the same two calls with the Full access key. If both behave as described, you know your keys are what you think they are before anyone builds on them.
Habits That Keep Keys Safe
- Keep the Full access key on the server only. Never ship it in a mobile app, a browser bundle or a public repository.
- Give each system its own key. When one system is retired or compromised, you revoke one key and nothing else breaks.
- Prefer Read only wherever a system only looks.
- Record each key in your own inventory with its access level, owner and use, since the page shows only a prefix and the last four characters.
Your customers' browsers need a different credential, not your secret key. The embed icon on each Product page shows three steps: create a user session token on your server, embed the component, and listen for its events.
Revoke a Key That Should Not Exist
Each row has a trash icon labelled "Revoke key" that opens a confirmation dialog. Revoking is immediate and cannot be undone, and anything still using the key starts failing right away. If a key may have leaked, create its replacement first, deploy it, then revoke the old one. If you are certain the key is exposed and cannot wait, revoke first and accept the downtime.
Turn On Webhooks
Webhooks tell your system when something happens at Slate, so you do not have to keep asking. Go to Developers, then Webhooks. The page is titled "Webhook endpoints that receive Slate events". Flip the switch "Enable Webhooks". An embedded webhook portal appears, where you add endpoints, choose which events each one receives and see delivery attempts and retries. Webhooks are self-serve, and each environment has its own setup.
- Stand up an HTTPS URL that accepts a POST and returns a 2xx status quickly.
- In the portal, add that URL as an endpoint and choose events. Start with the two or three your product reacts to first.
- Trigger something in sandbox, such as creating a customer, and watch the delivery appear in the portal.
- If a delivery fails, read the attempt in the portal, fix your side and trigger it again.
Every event has the same shape: event_type, a data object with the id of the thing that changed, and a timestamp. Webhooks are notifications, not payloads, so fetch the current state from the API when one arrives. Examples are customer.created, preapproval.created, application.submitted, application.approved, financing-agreement.payment.failed and credit-line.draw.funded. There are dozens, and the portal lists them all.
Verify Every Delivery
Slate delivers webhooks with Svix and signs every request. Each carries svix-id, svix-timestamp and svix-signature headers, and each endpoint has a signing secret starting whsec_, shown with its webhook information in the dashboard. The svix-id is the same when a message is resent, so store it and skip repeats. Check the signature on the raw body before you trust anything.
import crypto from "node:crypto";
export function verify(rawBody, headers, secret) {
const key = Buffer.from(secret.replace("whsec_", ""), "base64");
const signed = `${headers["svix-id"]}.${headers["svix-timestamp"]}.${rawBody}`;
const expected = crypto.createHmac("sha256", key).update(signed).digest("base64");
return headers["svix-signature"].split(" ").some((part) => {
const sig = part.split(",")[1] ?? "";
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
});
}
Return 200 quickly and do the real work afterwards, so a slow database never turns into a failed delivery. Make your handler safe to run twice.
Choosing Events Without Drowning
It is tempting to subscribe to everything. Every event you subscribe to is one your handler has to understand, log and test. Begin with the smallest set that drives something your customer can see.
| If your product needs to | Start with |
|---|---|
| Show a customer that an offer exists | preapproval.created |
| Update a status line when someone applies | application.submitted, application.approved, application.rejected |
| Reflect that money has been funded | financing-agreement.created, financing-agreement.disbursed |
| Alert your team to a failed payment | financing-agreement.payment.failed |
| Send your own customer emails | The event listed next to each email on the Emails, Templates tab |
Repeat Everything in Live
Sandbox and live do not share keys or webhook settings. In the live dashboard, open Developers and repeat both steps: create the keys you need, enable webhooks, add the production endpoint and choose the events. Write the setup down once as a short runbook, then follow it twice.
Common Questions
Can I name a key or set an expiry?
Not in the dashboard. Keep your own record of where each key is used, and replace keys on your own schedule.
What does a Read only key do on a write?
The write is refused with a 403. Reads work normally.
I closed the dialog without copying my key. Now what?
Create a new key, update whatever needs it and revoke the lost one. The dialog shows a key only once.
Do my sandbox webhook endpoints carry over to live?
No. Webhooks are set up per environment, so add your endpoint again in live.
Is there an SDK?
The Partners SDK is published as @tryslatehq/partners-sdk on npm, and the help panel links to it.
Read next: Your First Week on Slate · What to Expect When You’re Onboarding With Slate