API Keys

In A Nutshell
In a nutshell

Paystack has three types of API keys. Public keys initiate payments from your frontend, secret keys call the full API from your backend, and restricted keys call only the endpoints you grant them.

Key types

Every integration has a public key and a secret key for test mode and for live mode. Test keys start with pk_test_ or sk_test_, and live keys start with pk_live_ or sk_live_. Restricted keys are optional, and you create them on the dashboard when you need them.

TypePrefixWhere you use itWhat it can do
Public keypk_FrontendInitiate transactions with Paystack Inline and the Mobile SDKs
Secret keysk_BackendCall every endpoint in the Paystack API and verify the deprecated x-paystack-signature webhook header
Restricted keyrk_BackendCall only the endpoints covered by its scopes

You use your public key in code that runs on your customer's device, so it's the only key that's safe to expose. Your secret key gives full access to the API. Once you generate a webhook signing secret, Paystack signs webhook events with it, not with a restricted key. Your secret key only signs the deprecated x-paystack-signature header. If your integration computes checkout hashes for Paystack Inline, or calls an endpoint that doesn't have a scope yet, you need your secret key for that too.

A restricted key is useful when a service only needs part of the API. For example, a reporting job that reads transactions only needs transactions:read. It's also the safer way to give a third party access to your account: you can scope the key to what their tool does, and revoke it when you stop working with them. If a restricted key leaks, it can only call the endpoints its scopes cover.

Keep secret and restricted keys on your server

Don't put a secret key or a restricted key in frontend code, a mobile app, or a code repository.

To learn how to send your key with a request, how test and live modes work, and how to set up IP allowlisting, check out the Authentication page.

Rotate your secret keys

You should rotate your secret keys on a regular schedule, and right away if you suspect one has leaked. You generate new keys on the dashboard, then choose how long your current keys keep working while you move your systems over to the new ones.

Before you begin!

Generating new keys replaces your live and test secret keys together. Before you start, find every place that uses either key: your production and staging servers, background workers and scheduled jobs, CI/CD secrets and your secrets manager, and your webhook verification code if it checks x-paystack-signature. Each of these needs the new key before your current key expires.

Generate new secret keys

  1. Open the Developers overview page on your dashboard.
  2. Click Generate new secret key.
  3. Under How soon should your old keys expire?, choose an expiry time.
  4. Under Enter your account password to confirm, enter your password, then click Generate new secret keys.
  5. Copy your new live and test secret keys.

When your current keys expire, Paystack sends you an email to let you know. The email doesn't contain your key values.

Choose an expiry time

Your new keys work from the moment you confirm, and your current keys keep working until the expiry time you choose. The table below shows each option and when to use it:

OptionWhen to use it
ImmediatelyYou suspect a secret key has been exposed
30 minutesYou can update every system that uses the key within 30 minutes
2 hoursYou're doing a planned rotation
If a key has been exposed

Choose Immediately. Every request made with the exposed key fails from that moment, including requests from your own servers, so have the new key ready to deploy.

Update your servers

Replace the secret key in each environment, then deploy or restart every service that reads it. We recommend reading the key from an environment variable or your secrets manager rather than from source code, so the next rotation is a configuration change and not a code change.

To confirm a server is using the new key, call the Check BalanceAPI endpoint from that server. A 200 response with "status": true means the key works:

1curl https://api.paystack.co/balance \
2 -H "Authorization: Bearer $PAYSTACK_SECRET_KEY"

Repeat the check with your test secret key in your test environments. Once your current key expires, any server still using it gets a 401 response with the message Invalid key. If you see this, make sure live systems have the new sk_live_ key and test systems have the new sk_test_ key, then redeploy.

Update your webhook signature validation

If you verify the deprecated x-paystack-signature header, update your signature validation code after you rotate. Paystack signs that header with your secret key. Until your current key expires, check each event's signature against both keys and accept it if either one matches. Once the current key expires, remove it from your configuration.

Restricted keys

Using a plugin?

If you connect to Paystack through a plugin, check that it supports restricted keys and webhook signing secrets before you delete your secret key.

A restricted key authenticates requests the same way a secret key does, with Authorization: Bearer rk_..., but it can only call the endpoints its scopes allow. Every restricted key has a name that describes what it's for and at least one scope, such as transactions:read. You can also give it an expiry date, after which the key stops working.

You can change a key's name and scopes after you create it, but not its expiry date. An expiry date can be at most a year away, or you can choose No expiration. An integration can have up to 50 active restricted keys. Because restricted keys grant access to the API, Paystack asks for your dashboard password whenever you create, edit, or delete one.

Limitations

Restricted keys can't manage API keys or change your integration settings, apart from the payment session timeout. Any endpoint that isn't covered by a scope rejects a restricted key, so use the dashboard or your secret key for those.

Create a restricted key

Before you create a key, decide which scopes the service needs and grant only those. Switch your dashboard to test or live mode first: a key created in test mode starts with rk_test_ and only works with test data.

  1. Open the API configuration page on your dashboard, and under Restricted API keys, click Create restricted key.
  2. Under Choose permissions, select Read or Write for each resource the key needs, then click Continue.
  3. Under Name and expiration, enter a Name that describes what the key is for, such as Reporting service. Then choose an Expiration: 7, 30, 60, or 90 days, a custom date, or No expiration.
  4. Click Create restricted key, then enter your password to confirm.
  5. Copy the key and store it in your secrets manager. The dashboard shows the full key only once.

Make a request with a restricted key

You send a restricted key in the Authorization header, just as you would a secret key. This request calls the List TransactionsAPI endpoint with a key that has the transactions:read scope:

1curl "https://api.paystack.co/transaction?perPage=1" \
2 -H "Authorization: Bearer $PAYSTACK_RESTRICTED_KEY"

If you've set up the key and scope correctly, you get a 200 response:

1{
2 "status": true,
3 "message": "Transactions retrieved",
4 "data": [
5 {
6 "id": 4099260516,
7 "domain": "test",
8 "status": "success",
9 "reference": "re4lyvq3s3",
10 "amount": 40333,
11 "currency": "NGN",
12 "paid_at": "2024-08-22T09:15:02.000Z"
13 }
14 ],
15 "meta": {
16 "next": "dW5kZWZpbmVkOjQwMTM3MDk2MzU=",
17 "previous": null,
18 "perPage": 1
19 }
20}

If you get an error instead, see Restricted key errors.

Replace or delete a restricted key

You can't rotate a restricted key on the dashboard. To replace one, create a new key with the same scopes, update the service that uses it, then delete the old key.

Delete a restricted key when nothing should use it again, such as when you stop working with the third party that held it. Find the key under Restricted API keys, choose Delete, then click Delete key and enter your password. Any request using the key stops working right away, and you can't undo this.

Scopes

A scope grants a restricted key access to one resource at one level, and it's written as resource:level, for example transactions:read. The read level grants the endpoints that retrieve a resource, and write grants the endpoints that create, update, or delete it. A write scope includes read for the same resource, so transactions:write also grants transactions:read.

The table below lists the levels each resource supports:

ResourceLevels
accountread, write
apple_paywrite
balanceread
bank_accountsread, write
banksread, write
bulk_chargesread, write
connectwrite
customer_insightsread
customersread, write
direct_debitread, write
disputes_refundsread, write
metricsread, write
payment_pagesread, write
payment_requestsread, write
payoutswrite
plansread, write
preauthorizationsread, write
productsread, write
settlementsread, write
subaccountsread, write
terminalsread, write
transactionsread, write
transfersread, write
verificationwrite
virtual_accountsread, write
webhooksread, write
Account scopes

The account scopes cover your integration's payment session timeout: account:read for the Fetch TimeoutAPI endpoint, and account:write for the Update TimeoutAPI endpoint. If you connect to Paystack through a plugin, include the account:read scope in the plugin's restricted key.

Apple Pay domain endpoints use the transactions scopes: transactions:read to list your domains, and transactions:write to register or remove one. The apple_pay, bank_accounts, and metrics scopes don't cover any endpoints yet.

Restricted key errors

Paystack checks the key first, then the key's scopes, then the request itself. This means a request with a missing scope gets a 403 response even if its body is also invalid. The table below shows each error a restricted key can get:

StatusMeaning
401The key is unknown, malformed, deleted, or expired. The message is Invalid key, the same as for an invalid secret key.
403The key is valid but doesn't have the scope the endpoint requires. Add the scope to the key on the dashboard, or use a key that has it.
400The key has the required scope, but the request is invalid. This is the same validation error a secret key gets.

A 403 response looks like this:

1{
2 "status": false,
3 "message": "This restricted key is not permitted to perform this action"
4}