Skip to main content
Send your API key in collectwise_key on authenticated routes. Keys must be active and unexpired, and their organization must be active. Live and sandbox behavior remains attached to the key. Manage keys and optional controls in the dashboard’s API Keys page as an organization member with access to that page. Creating, replacing or revoking a key uses your signed-in dashboard session. Signing-secret and organization security-policy changes require recent identity verification.

Signed requests (CW1)

Signing is required when enabled on the key or for the organization. The signing secret is separate from the API key. It is generated as 32 random bytes and displayed once as unpadded base64url. Decode that value before using it as the HMAC key; do not HMAC with its text representation. Store both credentials securely and never put them in a URL or logs. For each request, compute SHA-256 over the exact body bytes you will send. Empty body means zero bytes, not {}. Join these six fields with ASCII newline (\n), with no trailing newline:
Keep query ordering, repeated parameters, percent-encoding case and JSON whitespace exactly as sent. Do not decode, sort or reserialize after signing. The hostname is not included. Use UTF-8 for the canonical string. Add:
  • collectwise_key: the API key.
  • x-cw-timestamp: the same canonical decimal integer timestamp.
  • x-cw-signature: v1= followed by lowercase hex HMAC-SHA256 of the canonical string.
The API accepts timestamps within ±300 seconds of its clock, inclusive. Synchronize your clock. Duplicate signing/authentication headers are rejected. Supported nonempty request bodies are JSON in UTF-8; compression and oversized bodies are rejected (100 KiB limit). Authentication precedes JSON parsing, after raw body capture and body-type/size checks. The Node.js and Python examples below compute headers without sending a request. Pass their body Buffer/bytes unchanged to your HTTP client. Supply the API-key header separately. Prepare a fresh timestamp/signature for each new attempt. Replay and retries: a signature is reusable while its timestamp is accepted. These are not single-use requests; there is no nonce store. A timeout or lost response after a send can have an unknown outcome. Retrying can duplicate a voicemail, text or other action. Signing does not add send idempotency.

Test before enabling enforcement

Send POST /security/verify with the API-key header and an empty body or {}. Sign those exact bytes when a usable signing secret exists, even if signing enforcement is still off.
  • Valid key + usable current/grace secret: a valid signature is required before any diagnostic disclosure.
  • Required signing + no usable secret: generic 401.
  • Signing off + no usable secret: signature is reported as skipped.
  • For an authenticated diagnostic only, an IP mismatch is reported rather than blocked. Normal business routes still enforce the allowlist.
Example authenticated response (documentation-only IP):
ipMatch means the observed source IP matches a saved range, independently of whether enforcement is enabled. With no saved ranges it is false. A 200 diagnostic response does not mean a business request would pass the allowlist; inspect both fields. The source IP comes from the trusted API Gateway event, never arbitrary forwarded headers. An unavailable trusted source produces a generic 503. This endpoint does not send messages or change your security settings. Authenticated diagnostics count toward the organization-wide request allowance below. Responses are private, no-store.

Network allowlists

Saved IPv4/IPv6 addresses and CIDR ranges apply to every key in the organization when enabled. Include the application’s public outgoing IPs. You cannot enable an empty allowlist. The diagnostic endpoint helps check the observed IP before enforcement. All IPs in examples, such as 203.0.113.0/24, are reserved documentation values, not proposed customer settings.

Provision, rotate and recover

Provision a signing secret, configure the application, verify a signed diagnostic, then enable signing. Organization-wide signing requires every active key to have a usable secret; expired keys still marked active may need revocation. New or regenerated keys under required signing cannot call business routes until a secret is separately provisioned. Regeneration preserves expiration, environment and signing requirements and invalidates the old key and its secrets. Rotation requires an explicit choice: no grace, 24 hours or 7 days. At most one current and one unexpired previous secret are eligible. You cannot rotate again or provision a replacement while a previous secret remains in grace: wait or explicitly revoke it. Revoking the current secret does not silently revoke a separate previous secret. Expired/revoked versions cannot be used even if decryption was cached. After reveal, refresh/history can show metadata but cannot reveal the secret again. Do not automatically replay a management mutation after an uncertain response. Dashboard access is separate from the API data-plane allowlist, allowing an authorized organization member to correct a lockout. Contact support if dashboard recovery is unavailable.

Errors and rate limits

  • 401: invalid/inactive/expired key or required signing failure; generic response, no IP details.
  • 403: authenticated business request outside an enforced allowlist.
  • 429: organization-wide request allowance exhausted; {"error":"Too many requests"} with Retry-After in seconds.
  • 400/413/415: malformed JSON, oversized or unsupported body, as applicable.
  • 503: authentication/security dependency or trusted-metadata failure; enforcement fails closed.

Organization-wide request allowance

Your organization shares a rate limit across all API keys and authenticated endpoints. The allowance replenishes continuously at 50 requests per second, with bursts of up to 3,000 requests when capacity is available. If you receive 429 Too Many Requests, wait at least the number of seconds specified in Retry-After before retrying. Pace requests across your applications to stay within the shared limit. For signed requests, generate a fresh timestamp and signature before retrying. See retry guidance for handling timeouts and lost responses. When present, these response headers describe your allowance:

Signing examples