Vigilae Connect

An API you can read before you sign.

The specification is public, the surfaces are neutral, the webhook signature can be verified in ten lines on your side. This page documents what the API exposes today — nothing more, and that is deliberate: what isn't shipped isn't documented.

  • OpenAPI specification readable without a key or an account
  • Never a suspicious activity report, never client verbatim
  • Signed webhooks, verifiable outside Vigilae

Served by the API itself: the contract you read is the one that runs.

The perimeter

Neutral surfaces, by construction.

The API exposes what an integrator can consume without touching the secrecy of the files: the monitoring journal and counters. The content of a vigilance file, the documents, the suspicious activity reports do not transit through this API — not a plan limitation, the architecture.

Monitoring journal

The firm's pKYC events — expired document, change of beneficial owner, re-screening to review — in neutral form: sequence, type, severity, date. Responses always bounded to 500 events.

Portfolio aggregates

Counters, never a file: volumes by status, delays, completeness. Enough to render a dashboard in your tool without a single client datum entering it.

Qualification

The only write: qualifying a journal event (status qualifie or clos, disposition planifie, traite or ecarte). It requires the write scope — least privilege is the rule, not an option.

The API is designed server-to-server: a key in code shipped to the browser is a published key. Have a server-side proxy hold the key, never the page.

Keys

Scoped keys, shown once, revocable immediately.

  • Format. Every key starts with vgk_ and is sent as Authorization: Bearer vgk_…. The secret is shown only at creation: we keep nothing but its SHA-256 digest.
  • Scopes. lecture (read, the default) and ecriture (write). A key without the required scope receives a 403 — see #scopes.
  • Expiry. One year after creation (visible in the firm's console). An expired key receives an explicit 401 — see #cle-expiree.
  • Rate. 60 requests/minute per key (overridable per key). A 429 carries Retry-After and the X-RateLimit-Limit / -Remaining / -Reset headers.
  • Revocation. Immediate, from the console. Resolution is by digest: keys cannot be enumerated.
Quickstart

Three curl calls and you have seen it all.

# Health + key authentication curl -s https://vigilae.org/api/v1/sante \ -H "Authorization: Bearer vgk_your_key" # Monitoring journal, from the beginning, in pages of 100 curl -s "https://vigilae.org/api/v1/evenements?depuisSeq=0&limite=100" \ -H "Authorization: Bearer vgk_your_key" # Qualify event 42 (write scope) curl -s -X POST https://vigilae.org/api/v1/evenements/42/qualifier \ -H "Authorization: Bearer vgk_your_key" \ -H "Content-Type: application/json" \ -d '{"statut":"qualifie","disposition":"traite"}'

Pagination, in one rule

Pass depuisSeq (0 on the first call) and limite (capped at 500): the response is sorted by ascending seq and returns prochainSeq, to pass back as is on the next call. A page shorter than limite means the end of the journal — prochainSeq then stays stable and serves as a polling cursor. Without depuisSeq, you get the "most recent first" view, bounded to 500.

The portfolio is queried on /api/v1/portefeuille/agregats — counters, one response, no pagination.

Webhooks

Signed, timestamped, delivered at least once.

Rather than polling the journal, receive it: Vigilae delivers events to your URL, in order, in batches of at most 100. Delivery is at-least-once — the cursor only advances on your 2xx, batch by batch — and idempotency is by seq: process each sequence exactly once (#idempotence).

Verifying the signature

Each delivery carries the header x-vigilae-signature: t=<unix>,v1=HMAC-SHA256(secret, t + "." + body). Recompute v1 from the raw body received, and reject any timestamp t beyond 5 min: that is the anti-replay. During a secret rotation the header carries one v1 per still-valid secret (24 h overlap): accept if any of them matches.

// Node — signature verification (no dependency) import { createHmac, timingSafeEqual } from 'node:crypto'; export function signatureValid(header, rawBody, secrets, toleranceMs = 5 * 60 * 1000) { const t = Number((/(?:^|,)t=(\d+)/.exec(header) || [])[1]); if (!t || Math.abs(Date.now() - t * 1000) > toleranceMs) return false; // anti-replay const received = [...header.matchAll(/v1=([0-9a-f]{64})/g)].map((m) => m[1]); return [].concat(secrets).some((secret) => { const expected = createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex'); return received.some((r) => r.length === expected.length && timingSafeEqual(Buffer.from(r), Buffer.from(expected))); }); }
# Python — same verification import hmac, hashlib, re, time def signature_valid(header: str, raw_body: bytes, secrets, tolerance_s: int = 300) -> bool: m = re.search(r"(?:^|,)t=(\d+)", header) if not m or abs(time.time() - int(m.group(1))) > tolerance_s: return False # anti-replay received = re.findall(r"v1=([0-9a-f]{64})", header) for secret in secrets: expected = hmac.new(secret.encode(), m.group(1).encode() + b"." + raw_body, hashlib.sha256).hexdigest() if any(hmac.compare_digest(expected, r) for r in received): return True return False

Transitional: the old sha256=HMAC(body) format is still emitted on x-vigilae-signature-legacy for receivers already in place; its removal is planned with webhooks v2. New receivers verify the timestamped scheme above, not the old one.

Rotation is triggered from the console (POST /connect/webhook/rotation on the application side): for 24 h the old secret still signs — time to deploy the new one on your side without a failure window.

Test environment

Sandbox: on request.

There is no self-service sandbox yet — we would rather tell you here than let you discover it. Write to contact@vigilae.org (subject "API access"): we open a trial firm with fictitious data for the duration of your integration, and we stay reachable while it progresses.

Each API error class has a stable address on the error reference: #authentification, #scopes, #cloisonnement, #debit, #signature… The API's error responses will point to these anchors.

The API exposes neither suspicious activity reports nor client verbatim, by construction (art. L.561-18 of the French CMF). No vigilance decision is taken by the API: it exposes and qualifies events; the professional decides.