Skip to main content

Data storage

DispatchQ stores the following data for each job:
FieldStoredNotes
payloadThe request body you send when creating a job
headersCustom headers you attach to the job
response_bodyThe response from your webhook endpoint
response_codeHTTP status code from your endpoint
urlThe target webhook URL
callback_urlWhere results are forwarded (if set)
All data is stored in Postgres with encryption at rest enabled by default (Neon).

Best practices

Don’t put raw secrets in payloads

Instead of:
{
  "url": "https://myapp.com/process",
  "payload": {
    "stripe_key": "sk_live_abc123",
    "database_url": "postgres://user:pass@host/db"
  }
}
Use references that your webhook resolves:
{
  "url": "https://myapp.com/process",
  "payload": {
    "stripe_key_ref": "vault://production/stripe-key",
    "job_type": "charge-customer"
  }
}
Your webhook 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 webhook endpoint requires authentication, prefer a pre-shared token that your endpoint validates, not a token with broad permissions:
{
  "url": "https://myapp.com/webhook",
  "headers": {
    "X-Webhook-Secret": "whsec_dispatchq_only_token"
  }
}
Use a dedicated, scoped token for DispatchQ webhooks rather than your main API keys.

Use HMAC verification on your endpoints

Every DispatchQ delivery includes an X-DispatchQ-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 DispatchQ, not an attacker hitting your endpoint.

Transport security

  • All connections to the DispatchQ API are over HTTPS/TLS
  • Webhook deliveries are always made over HTTPS (HTTP targets are rejected)
  • Postgres connections use TLS with certificate verification

Encryption at rest

All data stored in Postgres is encrypted at rest. Neon (our database provider) encrypts all data using AES-256.

Access control

  • Each account has its own API key
  • All API queries are scoped by account_id — you can only access your own jobs and schedules
  • 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",
  "payload": { "user_id": 42 },
  "redact_response": true
}
When redact_response is enabled, DispatchQ stores the status code and duration but discards the response body. Useful when your webhook returns sensitive data (PII, financial records, health data) that shouldn’t be retained.

Retention TTL

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

Per-account payload encryption

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