Get started
Your API keys
Test and live keys, secret and publishable, and your first authenticated request.
On this page
Every request to the AdProMaxPay API carries a key. The key tells the API which organization you are and which mode you work in, test or live.
The four kinds of key
| Prefix | Kind | Mode |
|---|---|---|
apx_sk_test_… | Secret | Test |
apx_pk_test_… | Publishable | Test |
apx_sk_live_… | Secret | Live |
apx_pk_live_… | Publishable | Live |
- A secret key acts for your whole organization. It belongs on your server, never in a web page or an app.
- A publishable key is made to sit in a web page or an app. Today every API route asks for a secret key.
- Test keys work as soon as you sign up. Live keys work once your account is activated.
Your sandbox's test secret key is shown once, when you sign up. Later keys are created on the dashboard's API keys page, and a secret key is shown only once, when it is created: store it then.
Send your first request
Put your test secret key in an environment variable, then ask the API who you are. Send the key as a bearer token, or as the user name of HTTP Basic authentication with an empty password.
The answer is your account: its ID, its activation status (sandbox until activation) and the API
version it uses.
curl https://pay-api.adpromax.com/v1/account \
-u "$APX_SECRET_KEY:"const response = await fetch('https://pay-api.adpromax.com/v1/account', {
headers: { Authorization: `Bearer ${process.env.APX_SECRET_KEY}` },
})
const account = await response.json()
if (!response.ok)
throw new Error(account.error.message)
console.log(account.id, account.activation_status)interface Account {
id: string
object: 'account'
business_name: string
activation_status: string
api_version: string
}
interface ApiError {
error: { type: string, code: string, message: string, request_id: string }
}
const response = await fetch('https://pay-api.adpromax.com/v1/account', {
headers: { Authorization: `Bearer ${process.env.APX_SECRET_KEY}` },
})
if (!response.ok) {
const { error } = (await response.json()) as ApiError
throw new Error(`${error.code}: ${error.message}`)
}
const account = (await response.json()) as Account
console.log(account.id, account.activation_status)import os
import requests
response = requests.get(
"https://pay-api.adpromax.com/v1/account",
auth=(os.environ["APX_SECRET_KEY"], ""),
)
account = response.json()
if not response.ok:
raise RuntimeError(account["error"]["message"])
print(account["id"], account["activation_status"])<?php
$ch = curl_init('https://pay-api.adpromax.com/v1/account');
curl_setopt_array($ch, [
CURLOPT_USERPWD => getenv('APX_SECRET_KEY') . ':',
CURLOPT_RETURNTRANSFER => true,
]);
$account = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($account['error']['message']);
}
echo $account['id'], ' ', $account['activation_status'], PHP_EOL;require 'json'
require 'net/http'
uri = URI('https://pay-api.adpromax.com/v1/account')
request = Net::HTTP::Get.new(uri)
request.basic_auth(ENV.fetch('APX_SECRET_KEY'), '')
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(request)
end
account = JSON.parse(response.body)
raise account.dig('error', 'message') unless response.is_a?(Net::HTTPSuccess)
puts "#{account['id']} #{account['activation_status']}"package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
)
type Account struct {
ID string `json:"id"`
BusinessName string `json:"business_name"`
ActivationStatus string `json:"activation_status"`
APIVersion string `json:"api_version"`
}
type APIError struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
func main() {
req, err := http.NewRequest(http.MethodGet, "https://pay-api.adpromax.com/v1/account", nil)
if err != nil {
log.Fatal(err)
}
req.SetBasicAuth(os.Getenv("APX_SECRET_KEY"), "")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode >= 400 {
var apiErr APIError
json.NewDecoder(res.Body).Decode(&apiErr)
log.Fatal(apiErr.Error.Message)
}
var account Account
if err := json.NewDecoder(res.Body).Decode(&account); err != nil {
log.Fatal(err)
}
fmt.Println(account.ID, account.ActivationStatus)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Account {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://pay-api.adpromax.com/v1/account"))
.header("Authorization", "Bearer " + System.getenv("APX_SECRET_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new IllegalStateException(response.body());
}
// The account as JSON: read it with your JSON library (Jackson, Gson…).
System.out.println(response.body());
}
}using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
var json = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("APX_SECRET_KEY"));
using var response = await http.GetAsync("https://pay-api.adpromax.com/v1/account");
if (!response.IsSuccessStatusCode)
{
var failure = await response.Content.ReadFromJsonAsync<ApiError>(json);
throw new InvalidOperationException(failure?.Error.Message);
}
var account = await response.Content.ReadFromJsonAsync<Account>(json);
Console.WriteLine($"{account!.Id} {account.ActivationStatus}");
record Account(string Id, string BusinessName, string ActivationStatus, string ApiVersion);
record ApiError(ApiErrorBody Error);
record ApiErrorBody(string Code, string Message);// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// serde = { version = "1", features = ["derive"] }
use serde::Deserialize;
#[derive(Deserialize)]
struct Account {
id: String,
activation_status: String,
}
#[derive(Deserialize)]
struct ApiError {
error: ErrorBody,
}
#[derive(Deserialize)]
struct ErrorBody {
message: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::blocking::Client::new()
.get("https://pay-api.adpromax.com/v1/account")
.bearer_auth(std::env::var("APX_SECRET_KEY")?)
.send()?;
if !response.status().is_success() {
let failure: ApiError = response.json()?;
return Err(failure.error.message.into());
}
let account: Account = response.json()?;
println!("{} {}", account.id, account.activation_status);
Ok(())
}{
"id": "org_01k7cz9q3m8v6t2x4b5n7p1r0s",
"object": "account",
"business_name": "Atlas Shop",
"country": "MA",
"default_currency": "mad",
"activation_status": "sandbox",
"capabilities": {
"card_payments": "inactive",
"cash_payments": "inactive"
},
"api_version": "2026-11-01",
"created": 1790847000
}When a key is refused
The API answers 401 or 403 with an error object; its code says why.
| Status | code | What happened |
|---|---|---|
| 401 | api_key_missing | The request carried no key. |
| 401 | api_key_invalid | The key does not exist. Check for a missing character. |
| 401 | api_key_revoked | The key was revoked. Use another one. |
| 401 | api_key_expired | The key was rolled and its overlap has ended. Use the new key. |
| 403 | secret_key_required | A publishable key was used where a secret key is needed. |
| 403 | account_inactive | The account is suspended or closed. |
| 403 | live_mode_not_activated | A live key was used before the account was activated. |
The error's message explains it in the language of your request, and its request_id identifies
the request if you write to support.
Keep secret keys secret
- Read the key from an environment variable or a secret store; never commit it to a repository.
- Never put a secret key in a web page, a mobile app or a support ticket.
- If a secret key may have leaked, revoke it on the dashboard and create a new one.
Rolling, revoking and the rest: Security.