Authentication
Authenticate every request to the Safravo API using a scoped API key.
The Safravo API authenticates requests using API keys. Every request must include your key in the X-API-Key header. Keys are scoped — they only grant access to the operations you explicitly permit when creating the key.
Generating an API key
- Go to Settings → Developers in the dashboard.
- Click Create API Key.
- Give the key a descriptive name (e.g.
CRM Integration) and select the scopes it needs. - Copy the full key immediately — it is shown only once and cannot be retrieved again.
The full API key is shown once at creation. Store it in your secrets manager immediately. If lost, revoke the key and create a new one.
Key format
All API keys follow this format:
saf_live_<48 hex characters>Example:
saf_live_7b58495bc9fc567bb5e1d38a381e690a3c2f1d8e4b7a9c0Sending the key
Pass your API key in the X-API-Key header on every request:
curl https://api.safravo.com/v1/templates \
-H "X-API-Key: saf_live_your_api_key_here"import axios from 'axios';
const client = axios.create({
baseURL: 'https://api.safravo.com',
headers: { 'X-API-Key': process.env.SAFRAVO_API_KEY },
});
// All subsequent calls automatically include the key
const { data } = await client.get('/v1/templates');import os
import httpx
client = httpx.Client(
base_url="https://api.safravo.com",
headers={"X-API-Key": os.environ["SAFRAVO_API_KEY"]},
timeout=30.0,
)
resp = client.get("/v1/templates")
resp.raise_for_status()$response = Http::withHeaders([
'X-API-Key' => env('SAFRAVO_API_KEY'),
])->get('https://api.safravo.com/v1/templates');package safravo
import (
"net/http"
"os"
)
type Client struct {
apiKey string
http *http.Client
}
func NewClient() *Client {
return &Client{
apiKey: os.Getenv("SAFRAVO_API_KEY"),
http: &http.Client{},
}
}
func (c *Client) newRequest(method, path string) *http.Request {
req, _ := http.NewRequest(method, "https://api.safravo.com"+path, nil)
req.Header.Set("X-API-Key", c.apiKey)
req.Header.Set("Content-Type", "application/json")
return req
}require 'net/http'
require 'json'
module Safravo
BASE = 'https://api.safravo.com'
def self.get(path)
uri = URI("#{BASE}#{path}")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = ENV['SAFRAVO_API_KEY']
Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
end
endScopes
Every API key is issued with one or more scopes that limit what it can do. Calling an endpoint without the required scope returns 403 Forbidden.
| Scope | Grants access to |
|---|---|
read:messages | Retrieve message status |
write:messages | Send messages and templates |
read:contacts | List and fetch contacts |
write:contacts | Create and update contacts |
read:templates | List approved WhatsApp templates |
read:broadcasts | View broadcast campaigns |
write:broadcasts | Create and send broadcasts |
read:webhooks | List webhook endpoints |
write:webhooks | Create and delete webhook endpoints |
read:conversations | Read conversation data |
write:conversations | Update conversations |
Least-privilege principle — create separate keys per integration. For example, one key for your CRM (contacts only) and another for your notification service (messages + templates). If a key is compromised, the blast radius stays small.
Security best practices
- Never commit keys — use environment variables or a secrets manager (AWS Secrets Manager, Doppler, Vercel env vars, GitHub Actions secrets).
- Rotate regularly — revoke and re-issue keys every 90 days, or immediately after a suspected breach.
- Restrict by scope — only grant the scopes an integration actually needs.
- Monitor usage — the Last Used timestamp in the dashboard alerts you to unexpected activity.
- Use HTTPS — all API calls must go to
https://api.safravo.com. HTTP is rejected.