Vaarta./API Guides

GUIDES

Three things to get right before you ship.

Practical notes for integrating the Competitive Signals API: how keys behave, what the limiter does under load, and how to verify a webhook you did not expect. For every endpoint and field, read the API Reference.

Authentication

Create a key in the dashboard under Settings → API Keys. The raw key is shown once — copy it immediately; only its hash is stored. Send it as a Bearer token on every request.

HEADER
Authorization: Bearer vt_live_xxxxxxxx…

A 401 means the key is missing, malformed, or revoked. The response never distinguishes which, to prevent key enumeration.

FIVE ACTIVE KEYS

A workspace may hold up to five at once, so rotation never needs downtime.

ROTATE FORWARD

Generate the new key, deploy it, then revoke the old one.

REVOCATION IS FINAL

Immediate and permanent. A revoked key keeps returning 401 forever.

Rate limits

PLAN TIERREQ / MIN/V1/SNAPSHOT PER HOUR
Free60Not available (pro+ only)
Pro3003
Team1,0003

The per-minute limit is enforced per key. Exceeding it returns 429 with a Retry-After header, in seconds until the window frees up. /v1/snapshot carries a separate hard cap of three accepted calls per rolling hour, because each one triggers a real collection run.

THE LIMITER FAILS CLOSED

If the rate-limit check itself errors, the request is rejected with 429 rather than passed through. Handle 429 as a retry, not as an outage.

Webhook signature verification

X-Vaarta-Signaturesha256= followed by the HMAC-SHA256 of the raw request body, hex-encoded.
X-Vaarta-TimestampUnix seconds at the moment the delivery was signed.
X-Vaarta-DeliveryA per-delivery UUID — useful as an idempotency key on your side.

Verify each delivery against your subscription secret, shown once on creation. The body is canonical JSON with object keys sorted. HMAC the exact raw bytes you receive — do not re-serialize.

RECEIVER
expected = "sha256=" + hex( HMAC_SHA256(secret, raw_request_body) )
# 1. constant-time compare against the header
if not constant_time_equals(expected, header["X-Vaarta-Signature"]):
reject  # 401, bad signature

# 2. reject stale deliveries (replay protection)
if abs(now_unix_seconds - header["X-Vaarta-Timestamp"]) > 300:
reject  # signature is valid but the delivery is too old

The timestamp defeats replay: an attacker who captures a valid signed payload cannot resubmit it later, because your receiver rejects deliveries outside a short freshness window — five minutes is a sensible default.