Authentication
How to authenticate API requests to Credo using your public and secret keys.
Every request to the Credo API must include an API key in the Authorization header. Credo uses two types of keys, each scoped to specific operations.
API keys
| Key | Prefix | Use for | Environment |
|---|---|---|---|
| Public Key | 0PUB... | Initializing transactions (client-safe) | Sandbox or Production |
| Secret Key | - | Verifying transactions, sensitive operations | Sandbox or Production |
Get your keys from Settings → Developer → API Keys in the sandbox dashboard or production dashboard.
Keep your secret key safe
Your secret key grants full access to verify and query transactions. Never expose it in frontend code, mobile apps, Git repositories, or client-side bundles. Store it in environment variables on your server.
Sending authenticated requests
Include your API key in the Authorization header of every request. There is no Bearer prefix - pass the key directly.
const response = await fetch("https://api.credodemo.com/transaction/initialize", {
method: "POST",
headers: {
"Authorization": process.env.CREDO_PUBLIC_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 50000,
email: "customer@example.com",
currency: "NGN",
bearer: 0,
channels: ["CARD", "BANK"],
initializeAccount: 0,
}),
});import requests
response = requests.post(
"https://api.credodemo.com/transaction/initialize",
headers={
"Authorization": os.environ["CREDO_PUBLIC_KEY"],
"Content-Type": "application/json",
},
json={
"amount": 50000,
"email": "customer@example.com",
"currency": "NGN",
"bearer": 0,
"channels": ["CARD", "BANK"],
"initializeAccount": 0,
},
)$ch = curl_init("https://api.credodemo.com/transaction/initialize");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: " . getenv("CREDO_PUBLIC_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 50000,
"email" => "customer@example.com",
"currency" => "NGN",
"bearer" => 0,
"channels" => ["CARD", "BANK"],
"initializeAccount" => 0,
]),
]);
$response = curl_exec($ch);import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class AuthenticationExample {
public static void main(String[] args) throws Exception {
String json = """
{
"amount": 50000,
"email": "customer@example.com",
"currency": "NGN",
"bearer": 0,
"channels": ["CARD", "BANK"],
"initializeAccount": 0
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.credodemo.com/transaction/initialize"))
.header("Authorization", System.getenv("CREDO_PUBLIC_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}using System.Text;
using System.Text.Json;
var payload = new
{
amount = 50000,
email = "customer@example.com",
currency = "NGN",
bearer = 0,
channels = new[] { "CARD", "BANK" },
initializeAccount = 0
};
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", Environment.GetEnvironmentVariable("CREDO_PUBLIC_KEY"));
var response = await client.PostAsync("https://api.credodemo.com/transaction/initialize", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);Which key to use
| Operation | Key |
|---|---|
| Initialize a transaction | Public key |
| Verify a transaction | Secret key |
| Direct card charge (initiate) | Secret key |
| Direct card charge (authorize) | Secret key |
| Webhook signature verification | Secret key |
Transaction initialization uses the public key because it runs in contexts where the key may be visible (browser, mobile app). All other operations require the secret key and must happen server-side.
Sandbox vs production keys
Each environment has its own key pair. They are not interchangeable.
| Sandbox | Production | |
|---|---|---|
| Dashboard | app.credodemo.com | app.credocentral.com |
| API base URL | api.credodemo.com | api.credocentral.com |
| Real charges | No | Yes |
| Keys work cross-environment | No | No |
A common pattern is to use environment variables to switch between them:
const BASE_URL = process.env.NODE_ENV === "production"
? "https://api.credocentral.com"
: "https://api.credodemo.com";
const API_KEY = process.env.NODE_ENV === "production"
? process.env.CREDO_LIVE_PUBLIC_KEY
: process.env.CREDO_TEST_PUBLIC_KEY;Authentication errors
If authentication fails, you'll receive one of these responses:
| Status | Message | Cause |
|---|---|---|
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Key doesn't have permission for this operation (e.g., using public key to verify) |
If you're getting 401 errors:
- Check that you're sending the key in the
Authorizationheader (not a query parameter) - Confirm you're using the right key for the right environment (sandbox key won't work on production)
- Verify the key hasn't been regenerated - regenerating invalidates the old key
- Make sure there's no extra whitespace or line breaks in the key
Regenerating keys
If your keys are compromised:
- Go to Settings → Developer → API Keys
- Click Regenerate next to the compromised key
- Update your application with the new key immediately
Regenerating a key invalidates the previous one immediately. Any requests using the old key will fail with a 401 error. Plan for minimal downtime when rotating keys.
Next steps
Was this page helpful?
Last updated on
