WinFactor Docs

Authentication

API keys, capability URLs, rate limits, and the error envelope

The platform uses two credential types, each scoped to exactly what it needs.

API keys

All general endpoints (/api/v1/submissions, /api/v1/quotes, …) authenticate with a per-organization API key:

curl "$WINFACTOR_URL/api/v1/quotes" \
  -H "Authorization: Bearer wf_live_..."
  • Create / revoke in Settings → Integrations → API keys (organization admins only).
  • The plaintext is shown once at creation. WinFactor stores only a peppered hash — a lost key cannot be recovered, only revoked and replaced.
  • Up to 10 active keys per organization. Give each integration its own key so you can revoke independently.
  • Optional read-only keys reject all mutating requests with 403 read_only_key.
  • lastUsedAt in the settings UI shows when each key last authenticated.

Capability URLs (pricing callbacks)

The live pricing write-back doesn't need an API key at all. Each pricing.calculated event carries a data.callback.url whose path contains a single-use capability token:

PUT https://app.winfactor.app/api/v1/configuration-sessions/{token}/adjustments
  • The token is the credential — no Authorization header required. This makes the callback a single HTTP step in ActivePieces.
  • It is minted fresh for every event and the previous token dies with the rotation.
  • Writes are accepted only within a bounded window after the event fired.
  • The token grants access to one configuration session only.

Treat callback URLs like passwords: don't log them and don't forward them outside your flow.

Rate limits

ScopeLimit
Per API key120 requests/minute
Per source IP (pre-auth)60 requests/minute
Capability-URL endpoints, per IP120 requests/minute

Exceeding a limit returns 429 with a Retry-After header (seconds). Back off and retry.

Error envelope

Every error is JSON with a stable machine-readable code:

{
  "error": {
    "code": "stale_config_hash",
    "message": "…human-readable…",
    "details": { "currentConfigHash": "sha256:…" }
  }
}
HTTPcodeMeaning
401unauthorizedMissing/invalid API key or capability token
403forbidden_planPlan lacks API access (details.requiredPlan)
403read_only_keyMutating request with a read-only key
403window_expiredAdjustment window for the session has closed
404not_foundUnknown ID — including IDs belonging to another organization
400validation_errorBody/query failed validation (details.issues)
409stale_config_hashAdjustment targeted a superseded configuration (details.currentConfigHash)
409quote_not_editableQuote is accepted/rejected/expired
409requires_reviseQuote was sent — pass revise: true to version it
409quote_not_sendableQuote can't be sent in its current status
409already_in_flightRedelivery requested for a pending event
410session_expiredConfiguration session has expired
422validation_errorLine items failed semantic validation
429rate_limitedSlow down (Retry-After header)
500internal_errorOur fault — safe to retry

Cross-organization IDs always return 404, never 403 — existence is not disclosed.

Lists & pagination

List endpoints return { "data": [...], "nextCursor": "..." | null }. Pass ?limit= (max 100, default 50) and ?cursor= to page:

curl "$WINFACTOR_URL/api/v1/submissions?limit=100&cursor=$NEXT" \
  -H "Authorization: Bearer $WINFACTOR_KEY"

All authenticated responses carry Cache-Control: no-store.

On this page