API, które można przeczytać przed podpisaniem.
Specyfikacja jest publiczna, a podpis webhooka można zweryfikować w dziesięciu linijkach po swojej stronie. Ta strona dokumentuje to, co API udostępnia dziś — nic więcej, i to celowo: czego nie wdrożono, tego nie dokumentujemy.
- Specyfikacja OpenAPI czytelna bez klucza i bez konta
- Nigdy zgłoszenie podejrzanej transakcji, nigdy dosłowne treści klienta
- Podpisane webhooki, weryfikowalne poza Vigilae
Serwowana przez samo API: kontrakt, który czytasz, to ten, który działa.
Cała ścieżka i dwa wyłączenia, które nie ulegną zmianie.
Twoje oprogramowanie może poprowadzić sprawę od początku do końca: utworzyć klienta, otworzyć sprawę, przesłać dokumenty, uruchomić weryfikację sankcyjną, zgłosić beneficjentów rzeczywistych, odczytać ocenę ryzyka i pobrać dossier dowodowe. Dwie rzeczy nigdy tędy nie przejdą, i nie jest to ograniczenie planu: żadnego zgłoszenia podejrzanej transakcji i żadnych dosłownych treści Twojego klienta. Pierwsze to czynność, którą ustawa zastrzega dla osoby dokonującej zgłoszenia; drugie nie ma czego szukać w kanale integracyjnym.
Sprawa od początku do końca
Klienci, sprawy, dokumenty potwierdzające, weryfikacja sankcyjna, beneficjenci rzeczywiści, ocena ryzyka, dossier dowodowe, kontrola integralności. Każdy zasób ma własne uprawnienie: Twój klucz otwiera wyłącznie to, co mu przyznano.
Dziennik i agregaty
Zdarzenia pKYC kancelarii — wygasły dokument, zmiana beneficjenta rzeczywistego, ponowna weryfikacja do obsługi — oraz liczniki portfela na Twój pulpit. Odpowiedź zawsze ograniczona, kursor stabilny.
To, co zapisujesz, ma swojego autora
Przesłać dokument, uruchomić weryfikację, zakwalifikować: każdy zapis wymaga własnego uprawnienia i odnotowuje operatora. Anonimowa kwalifikacja jest odrzucana — integracja rejestruje decyzję człowieka, sama żadnej nie podejmuje.
API jest zaprojektowane server-to-server: klucz w kodzie wysłanym do przeglądarki to klucz opublikowany. Klucz niech trzyma proxy po stronie serwera, nigdy strona.
Klucze o ograniczonych uprawnieniach, pokazywane raz, odwoływalne natychmiast.
- Format. Każdy klucz zaczyna się od
vgk_i jest przesyłany jakoAuthorization: Bearer vgk_…. Sekret jest pokazywany wyłącznie przy utworzeniu: przechowujemy jedynie jego skrót SHA-256. - Uprawnienia (scopes). Klucz niesie wyłącznie uprawnienia zaznaczone przy jego tworzeniu: ogólne
lecture(odczyt, domyślne) iecriture(zapis) albo drobne, zasób po zasobie —clients:,dossiers:,pieces:,criblage:(wlecturelubecriture),origine-fonds:lecture,journal:lecture.
Dziedziczenie idzie po przyrostku i tylko w jedną stronę:lecturepokrywa każde*:lecture,ecriturekażde*:ecriture; drobne uprawnienie nie otwiera niczego poza sobą.
Sześć uprawnień wypada poza tę parę i dlatego nie dziedziczy się z żadnego klucza ogólnego:alertes:qualifier,embed:emettre,adversemedia:consulter,conformite:consulter,dispositif:consulter,integrite:consulter. Każde deleguje się osobno, przy tworzeniu klucza.
Klucz bez wymaganego uprawnienia otrzymuje 403 — zob. #scopes. - Ważność. Rok od utworzenia (data widoczna w konsoli kancelarii). Wygasły klucz otrzymuje jednoznaczne 401 — zob. #cle-expiree.
Klucz może też przestać być akceptowany przed tą datą, gdy API nie wchodzi już w zakres abonamentu kancelarii. Zatrzymanie następuje wtedy co najmniej 30 dni po pierwszym e-mailu do kancelarii, w dniu podanym w drugim e-mailu, wysłanym co najmniej 7 dni wcześniej. Gdy tylko zostanie ustalona, ta data jest widoczna w konsoli kancelarii (polecoupure_lewGET /connect/cles), a każda odpowiedź na zaakceptowane wywołanie zapowiada ją w nagłówkuSunset, dopóki nie nadejdzie. Po tej dacie wywołanie otrzymuje 401 opisany w #authentification, z"motif": "fin_option_api"; jeśli API wróci do abonamentu, klucz znów jest akceptowany, aż do upływu jego własnego terminu ważności.
Odwołany klucz nie wraca wraz z API. A gdy cały abonament zostanie zawieszony lub się zakończy, klucze natychmiast przestają być akceptowane, bez zachowania tego terminu. - Limit żądań. 60 żądań na minutę na klucz (możliwy do zmiany per klucz). Odpowiedź 429 niesie
Retry-Afteroraz nagłówkiX-RateLimit-Limit / -Remaining / -Reset. - Odwołanie. Natychmiastowe, z konsoli. Rozpoznawanie odbywa się po skrócie: kluczy nie da się enumerować.
Trzy wywołania curl i masz obraz całości.
# Stan usługi + uwierzytelnienie kluczem
curl -s https://vigilae.org/api/v1/sante \
-H "Authorization: Bearer vgk_your_key"
# Dziennik monitoringu, od początku, stronami po 100
curl -s "https://vigilae.org/api/v1/evenements?depuisSeq=0&limite=100" \
-H "Authorization: Bearer vgk_your_key"
# Kwalifikacja zdarzenia 42 (uprawnienie zapisu)
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"}'Paginacja w jednej regule
Przekaż depuisSeq (0 przy pierwszym wywołaniu) i limite (maksymalnie 500): odpowiedź jest posortowana rosnąco po seq i zwraca prochainSeq, do przekazania bez zmian w kolejnym wywołaniu. Strona krótsza niż limite oznacza koniec dziennika — prochainSeq pozostaje wtedy stabilny i służy jako kursor odpytywania. Bez depuisSeq otrzymujesz widok „najnowsze najpierw”, ograniczony do 500.
Portfel odpytuje się na /api/v1/portefeuille/agregats — liczniki, jedna odpowiedź, bez paginacji.
Podpisane, ze znacznikiem czasu, dostarczane co najmniej raz.
Zamiast odpytywać dziennik, odbieraj go: Vigilae dostarcza zdarzenia na Twój URL, po kolei, w partiach po maksymalnie 100. Dostarczanie działa w trybie at-least-once — kursor przesuwa się tylko po Twoim 2xx, partia po partii — a idempotencja opiera się na seq: przetwórz każdą sekwencję dokładnie raz (#idempotence).
Weryfikacja podpisu
Każda dostawa niesie nagłówek x-vigilae-signature: t=<unix>,v1=HMAC-SHA256(secret, t + "." + body). Przelicz v1 z surowego otrzymanego body i odrzuć każdy znacznik czasu t starszy niż 5 min: to ochrona anty-replay. Podczas rotacji sekretu nagłówek niesie jedno v1 na każdy wciąż ważny sekret (24 h nakładania się): zaakceptuj, jeśli którekolwiek się zgadza.
// Node — weryfikacja podpisu (bez zależności)
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; // anty-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 — ta sama weryfikacja
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 # anty-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 FalsePrzejściowo: stary format sha256=HMAC(body) jest nadal emitowany w x-vigilae-signature-legacy dla już działających odbiorników; jego usunięcie planowane jest wraz z webhookami v2. Nowe odbiorniki weryfikują powyższy schemat ze znacznikiem czasu, nie stary.
Rotację wyzwala się z konsoli (POST /connect/webhook/rotation po stronie aplikacji): przez 24 h stary sekret nadal podpisuje — czas na wdrożenie nowego po Twojej stronie bez okna awarii.
Stan czujności, na Twoich ekranach.
Twoje oprogramowanie już tworzy sprawy przez API; widżety dają mu powierzchnię, której brakowało: pokazanie stanu czujności sprawy wprost na karcie klienta, bez budowania od nowa interfejsu zgodności. Cały przepływ to trzy kroki — Twój serwer wydaje krótkotrwały token, zwrócony URL trafia do iframe'a, widżet wyświetla. Wyświetlanie to jedyne, co robi: żadna decyzja, żadna kwalifikacja, żaden zapis nigdy nie przechodzi przez widżet. Kliknięcie otwiera aplikację Vigilae, gdzie działa zidentyfikowany człowiek.
1. Wydaj token — po stronie serwera, nigdy na stronie
Klucz vgk_ nigdy nie dotyka przeglądarki. Twój serwer wywołuje mint z dedykowanym uprawnieniem embed:emettre (zaznaczanym przy tworzeniu klucza, nigdy nie dziedziczonym) i tylko krótki token schodzi do strony: piętnaście minut domyślnie, w granicach 5-60, związany z jedną sprawą, jednym komponentem, jednym zadeklarowanym źródłem. Podróżuje we fragmencie URL — nie trafia ani do naszych logów, ani do Twoich.
# Token dla Compliance Button, etykieta wybrana z katalogu
curl -s -X POST https://vigilae.org/api/v1/embed/jetons \
-H "Authorization: Bearer vgk_your_key" \
-H "Content-Type: application/json" \
-d '{"dossier_id":"D123","composant":"bouton",
"audience":"https://your-software.example","libelle":"controler_client"}'
# 201 -> { "jeton": "…", "expire_le": "…",
# "url": "https://vigilae.org/embarque/bouton?c=…#…" }2. Umieść iframe — launcher, w dziesięciu liniach
Launcher vigilae-embed.js tworzy wyizolowany iframe (sandbox), przeprowadza uzgadnianie i podąża za rozmiarem widżetu (ograniczonym — iframe nigdy nie narzuca swojej wysokości Twojej stronie). Jeśli chodzi o CSP, Twoja strona otwiera jedną jedyną dyrektywę: frame-src https://vigilae.org. Nie jest wymagany żaden skrypt inline, żadna zależność. Ręcznie napisany iframe działa równie dobrze.
<script src="https://vigilae.org/embarque/vigilae-embed.js" defer></script>
<div id="vigilance"></div>// W Twoim skrypcie: url pochodzi z TWOJEGO serwera, który wywołał mint
var widget = VigilaeEmbed.monter({
conteneur: 'vigilance',
url: urlReturnedByTheMint,
renouvelerJeton: function () { // po wygaśnięciu: wydaj nowy token po stronie serwera
return fetch('/my-server/vigilae-token').then(function (r) { return r.text(); });
},
});
// widget.rafraichir(token) wprowadza nowy token; widget.demonter() usuwa wszystko.3. Compliance Button: Twoja etykieta, nasz stan
Etykieta przycisku pochodzi z zamkniętego katalogu — nigdy wolny tekst na powierzchni, która mówi o czujności; shell wyświetla te etykiety wyłącznie po francusku lub angielsku (parametr ?lang= w adresie URL widżetu), jeszcze nie w Twoim języku — poniższa lista podaje ich znaczenie:
controler_client— „Sprawdź tego klienta” (domyślnie)lancer_vigilance— „Rozpocznij należytą staranność”verifier_be— „Sprawdź beneficjentów rzeczywistych”preparer_dossier— „Przygotuj sprawę AML/CFT”
Wskaźnik stanu natomiast pokazuje stan obliczony przez Vigilae: a_jour (zielony — weryfikacja sankcyjna i ocena ryzyka aktualne), a_revoir (bursztynowy — weryfikacja sankcyjna lub ocena ryzyka nieaktualne, albo źródło zawiodło przy ostatnim przebiegu), alerte (czerwony — co najmniej jeden alert do rozpatrzenia), inconnu (szary — sprawa nigdy nie sprawdzona). Etykieta jest konfigurowalna, semantyka nigdy: kolor jest związany ze stanem wewnątrz samego shellu, który ignoruje każdą próbę nadpisania go przez postMessage. Sprawa w stanie alertu pokazuje alert, niezależnie od stylizacji.
Kontrakt postMessage w całości
Widżet emituje vigilae:pret, vigilae:taille (automatyczne dopasowanie rozmiaru), vigilae:expire (wydaj nowy token po stronie serwera, a następnie wyślij vigilae:jeton) i vigilae:ouvrir. Nigdy żadnej nazwy, ryzyka ani alertu w wiadomości: Twoje oprogramowanie ma już wszystko przez API server-to-server, a ten kanał nie stanie się drugim takim kanałem.
frame-ancestors shellu. Administrator deklaruje je bezpośrednio w Vigilae, na ekranie „Integracje i bezpieczeństwo”: dziesięć źródeł https:// co najwyżej, jawny host, nigdy symbol wieloznaczny; komponenty, które włącza; oraz masowe unieważnienie, które jednym gestem unieważnia wszystkie już wydane tokeny. http://localhost jest dopuszczony wyłącznie w kancelarii testowej — napisz na contact@vigilae.org (temat „Embedded widgets”), aby otworzyć taką na czas Twojej integracji. Brak zadeklarowanego źródła: mint odmawia z kodem 400. Instancja, w której magazyn źródeł nie jest podłączony: jawne 501 — zobacz #embed-indisponible.Sandbox: na życzenie.
Każda klasa błędów API ma stały adres w katalogu błędów: #authentification, #scopes, #cloisonnement, #debit, #signature… Odpowiedzi błędów API będą wskazywać te kotwice.
API nie udostępnia ani zgłoszeń podejrzanych transakcji, ani dosłownych treści klienta — z samej konstrukcji (art. L.561-18 francuskiego CMF). API nie podejmuje żadnej decyzji w zakresie należytej staranności: udostępnia i kwalifikuje zdarzenia; decyduje osoba wykonująca zawód.