Skip to main content

Data storage

SafeFetch stores the following data for each action:
FieldStoredNotes
bodyThe request body you send when creating an action
headersCustom headers you attach to the action
response_bodyThe response from your target API
response_codeHTTP status code from your target API
urlThe target URL
callbackWhere results are forwarded (if set)
All data is stored durably with encryption at rest enabled by default.

Best practices

Don’t put raw secrets in action bodies

Instead of:
{
  "url": "https://myapp.com/process",
  "body": {
    "stripe_key": "sk_live_abc123",
    "database_url": "postgres://user:pass@host/db"
  }
}
Use references that your endpoint resolves:
{
  "url": "https://myapp.com/process",
  "body": {
    "stripe_key_ref": "vault://production/stripe-key",
    "action_type": "charge-customer"
  }
}
Your endpoint handler looks up the actual secret from your vault/env at execution time.

Don’t put auth tokens in custom headers unless necessary

If your endpoint requires authentication, prefer a pre-shared token that your endpoint validates, not a token with broad permissions:
{
  "url": "https://myapp.com/api/process",
  "headers": {
    "X-Delivery-Secret": "whsec_safefetch_only_token"
  }
}
Use a dedicated, scoped token for SafeFetch deliveries rather than your main API keys.

Use HMAC verification on your endpoints

Every SafeFetch delivery includes an X-SafeFetch-Signature header. Always verify it:
import { createHmac, timingSafeEqual } from 'crypto';

function verify(body: string, signature: string, apiKey: string): boolean {
  const expected = `sha256=${createHmac('sha256', apiKey).update(body).digest('hex')}`;
  return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
This ensures the request actually came from SafeFetch, not an attacker hitting your API.

Transport security

  • All connections to the SafeFetch API are over HTTPS/TLS
  • Deliveries are always made over HTTPS (HTTP targets are rejected)
  • Database connections use TLS with certificate verification

Encryption at rest

All data is encrypted at rest.

Access control

  • Each account has its own API key
  • All API queries are scoped by account_id — you can only access your own actions
  • API keys are stored as hashed values (not plaintext) in the database

Coming soon

These features are planned for future releases.

Redacted responses

{
  "url": "https://myapp.com/sensitive-endpoint",
  "body": { "user_id": 42 },
  "redact_response": true
}
When redact_response is enabled, SafeFetch stores the status code and duration but discards the response body. Useful when your endpoint returns sensitive data (PII, financial records, health data) that shouldn’t be retained.

Retention TTL

{
  "url": "https://myapp.com/process",
  "body": { "file": "data.csv" },
  "retention": "7d"
}
Automatically purge all action data (body, headers, response) after the specified period. Data is permanently deleted — not soft-deleted. Supported values: 1d, 7d, 30d, 90d.

Per-account body encryption

Encrypt body, headers, and response_body with a per-account key. Even if the database is compromised, action data is unreadable without the account’s encryption key. Available on Team and Enterprise plans.