Authentication
Paytami's public API authenticates with a secret key in the Authorization header, Bearer style:
Authorization: Bearer sk_test_51a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6There's no username, password, or OAuth — a single key per integration.
Key format
sk_<environment>_<40 hex characters>sk_test_...— test environment, no real money moves.sk_live_...— live environment.
The key you use decides which environment each request runs against: Paytami looks it up in live first and, if not found there, in test. You never need to indicate the environment anywhere else in the request.
Getting your key
Keys are issued from the Paytami dashboard (dash.paytami.com), in your merchant's API Keys section. When you create a new key, the full value is shown once — Paytami only stores its hash, so if you lose it you'll need to revoke it and issue a new one.
Best practices
- Never expose a secret key in code that runs in the customer's browser (frontend JavaScript, mobile apps). Every call authenticated with
sk_...must originate from your server. - Use environment variables or a secrets manager — never hardcode the key in your repository.
- If you suspect a key leaked, revoke it from the dashboard and issue a new one immediately; the previous hash stops being valid instantly.
- Use
sk_test_...throughout development and integration, and switch tosk_live_...only when you're ready to charge for real. Data in both environments is completely separate: a payment created in test never shows up in live, or vice versa.
When authentication fails
A missing, invalid, revoked, expired, or wrong-type key always responds the same way:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"code": "unauthorized",
"message": "Invalid credentials"
}
}Paytami deliberately doesn't distinguish the exact reason in the response: detailing "the key expired" vs. "the key doesn't exist" helps someone probing keys at random more than it helps a legitimate integration, which already knows which key it issued.
Endpoints that don't require an api_key
Some routes are opened directly by the end customer's browser, which has no credentials — by design they don't carry Authorization:
GET /v1/checkout/{id}andGET /v1/payments/{id}/checkout_sessionGET /v1/payment_links/{id}andPOST /v1/payment_links/{id}/pay
These routes only expose the minimum needed to complete a payment your backend already created — never an operation that moves money without your api_key having been involved first.

