Safravo Logosafravo.com

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

  1. Go to Settings → Developers in the dashboard.
  2. Click Create API Key.
  3. Give the key a descriptive name (e.g. CRM Integration) and select the scopes it needs.
  4. 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_7b58495bc9fc567bb5e1d38a381e690a3c2f1d8e4b7a9c0

Sending 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
end

Scopes

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.

ScopeGrants access to
read:messagesRetrieve message status
write:messagesSend messages and templates
read:contactsList and fetch contacts
write:contactsCreate and update contacts
read:templatesList approved WhatsApp templates
read:broadcastsView broadcast campaigns
write:broadcastsCreate and send broadcasts
read:webhooksList webhook endpoints
write:webhooksCreate and delete webhook endpoints
read:conversationsRead conversation data
write:conversationsUpdate 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.

On this page