Security Best Practices
Protect your Orbit integration with proper API key management, webhook signature verification, and security hardening.
API Key Management
Key Types
Orbit uses three types of API keys:
| Key Type | Prefix | Usage | Permissions |
|---|
| Live Secret Key | dv_live_sk_ | Server-side only | Full API access |
| Test Secret Key | dv_test_sk_ | Server-side testing | Sandbox only |
| Public Key | dv_live_pk_ | Client-side (web SDK) | Limited read-only |
Key Security Rules
- Never expose secret keys in client-side code. Secret keys (
sk_) should only be used in server-side environments.
❌ Client-side JavaScript
const orbit = new Devotel({ apiKey: 'dv_live_sk_xxxx' }) // NEVER
✅ Server-side only
// Node.js backend, Python server, etc.
const orbit = new Devotel({ apiKey: process.env.DEVOTEL_API_KEY })
- Use environment variables. Never hardcode keys in source code.
# .env (never commit this file)
DEVOTEL_API_KEY=dv_live_sk_your_key_here
-
Rotate keys regularly. Generate new keys quarterly and revoke old ones.
-
Use separate keys per environment. Use test keys (
dv_test_sk_) for development.
-
Restrict key permissions. Create keys with minimum required scopes in the dashboard under Settings > API Keys.
Revoking a Compromised Key
If a key is exposed:
- Go to Settings > API Keys in the Orbit dashboard
- Click Revoke on the compromised key
- Generate a new key
- Update your application configuration immediately
Revoking a key is immediate and irreversible. All requests using the revoked key will return 401 INVALID_API_KEY.
Webhook Verification
Every webhook from Orbit includes an HMAC-SHA256 signature in the X-Devotel-Signature header. Always verify this signature before processing webhook payloads.
How Verification Works
- Orbit signs the raw request body using your webhook secret
- The signature is sent in the
X-Devotel-Signature header
- Your server recomputes the signature and compares it
Implementation
Node.js
import crypto from 'node:crypto'
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
)
}
app.post('/webhooks/orbit', (req, res) => {
const signature = req.headers['x-devotel-signature']
const isValid = verifyWebhookSignature(
req.rawBody,
signature,
'whsec_your_secret',
)
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' })
}
// Process the webhook
const event = req.body
res.status(200).json({ received: true })
})
Python
import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
@app.route("/webhooks/orbit", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Devotel-Signature")
if not verify_webhook_signature(request.data, signature, "whsec_your_secret"):
return jsonify({"error": "Invalid signature"}), 401
event = request.get_json()
return jsonify({"received": True}), 200
func verifyWebhookSignature(payload []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}
Webhook Security Checklist
Transport Security
HTTPS Required
All Orbit API endpoints require HTTPS (https://orbit-api.devotel.io). HTTP requests are rejected.
TLS Requirements
- Minimum TLS 1.2
- TLS 1.3 recommended
- Weak cipher suites are not supported
Webhook Endpoint Requirements
Your webhook endpoints must:
- Use HTTPS with a valid SSL certificate (not self-signed)
- Support TLS 1.2 or higher
- Respond within 30 seconds
- Return a
2xx status code to acknowledge receipt
IP Allowlisting
If your firewall restricts inbound traffic, allowlist Orbit’s webhook delivery IPs:
34.141.0.0/16 (europe-west1 — primary)
35.195.0.0/16 (europe-west1 — secondary)
IP ranges may change. Subscribe to the Orbit status page for notifications about infrastructure changes.
Data Security
PII Handling
- Orbit masks phone numbers in logs (
+1415555****)
- API responses include full data; mask PII in your own logs
- Use metadata fields for internal identifiers instead of PII
Data Retention
| Data Type | Retention | Notes |
|---|
| Message content | 90 days | Configurable per account |
| Call recordings | 30 days | Configurable; auto-deleted after |
| Webhook delivery logs | 30 days | Available in dashboard |
| API access logs | 1 year | Includes request IDs |
Encryption
- In transit: TLS 1.2+ for all API and webhook traffic
- At rest: AES-256 encryption for all stored data
- Recordings: Encrypted at rest with per-tenant keys
RBAC (Role-Based Access Control)
Orbit supports five roles with increasing permissions:
| Role | API Keys | Send Messages | Manage Agents | Billing | Team |
|---|
viewer | Read only | No | No | No | No |
developer | Create/manage | Yes | Yes | No | No |
admin | Full access | Yes | Yes | View | Invite |
billing | No | No | No | Full | No |
owner | Full access | Yes | Yes | Full | Full |
Assign the minimum role needed for each team member.
Orbit API responses include security headers:
| Header | Value |
|---|
X-Request-Id | Unique request identifier for tracing |
Strict-Transport-Security | max-age=31536000; includeSubDomains |
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
Found a security vulnerability? Report it to security@devotel.io. We take all reports seriously and respond within 24 hours.