API GeoPulse — référence v1
Base : https://geo-pulse.app/api/v1
L'API donne accès en lecture seule à ce que GeoPulse produit chaque jour : prix de 50 actifs, événements géopolitiques scorés par IA, signaux ouverts, indice composite et corrélations. Aucun endpoint n'écrit, ne modifie un compte ni n'expose de donnée personnelle.
Elle est réservée au plan API. Pour y accéder aujourd'hui, contactez-nous — le plan n'est pas encore ouvert en libre-service.
Authentification
Chaque requête porte votre clé, au choix :
curl -H "X-API-Key: gp_live_votrecle" https://geo-pulse.app/api/v1/prices
curl -H "Authorization: Bearer gp_live_votrecle" https://geo-pulse.app/api/v1/prices
Les clés se créent et se révoquent depuis votre compte → onglet API. Une clé n'est affichée qu'une seule fois, à sa création : nous n'en stockons que l'empreinte (SHA-256), et nous sommes donc incapables de vous la rappeler. Perdue, elle se remplace — révoquez-la et créez-en une autre.
Jusqu'à 5 clés actives simultanément : une par environnement, ce qui permet d'en révoquer une sans interrompre les autres.
Limites
| valeur | |
|---|---|
| Débit | 60 requêtes/minute, par clé |
| Quota | 50 000 requêtes/jour, par clé, remis à zéro à 00:00 UTC |
Chaque réponse porte l'état de vos compteurs :
X-RateLimit-Limit: 50000 X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining: 49987 X-RateLimit-Remaining-Minute: 58
Un dépassement de débit renvoie 429 avec un en-tête Retry-After en secondes — et
ne consomme pas de quota journalier : une rafale mal réglée ne peut pas vider votre
abonnement sans vous avoir rien rendu. Un dépassement de quota renvoie également
429, jusqu'à la remise à zéro.
À quelle fréquence appeler ?
Nos données ne changent pas plus vite que nous ne les collectons. Appeler au-delà de ces cadences renvoie la même réponse :
| donnée | rafraîchissement |
|---|---|
| Prix des 15 actifs du moteur | 30 s (cryptos) à 2 min — même cadence en crise depuis le 12/09/2026 |
| Prix des 35 actifs observés | 15 min |
| Événements | 5 min |
| Signaux | toutes les 2 h, plus dès réception d'un événement de sévérité ≥ 7 (les articles NewsData arrivent ~12 h après publication) |
| Indice composite | toutes les heures |
| Corrélations | toutes les 15 min |
Un client qui interroge l'ensemble du produit une fois par minute consomme environ 1 440 requêtes par jour, soit 3 % du quota.
Endpoints
GET / — documentation exécutable
Public, sans clé. Renvoie la liste des endpoints, les limites en vigueur et les cadences de rafraîchissement. Utile pour vérifier une version sans lire cette page.
GET /assets — registre des actifs
{ "count": 50,
"assets": [ { "symbol": "XAU", "name": "Or", "category": "commodity", "unit": "$",
"tier": "signals", "covered_by_rules": true, "family": null } ] }
tier dit la cadence de collecte : signals (15 actifs, collecte rapide, panier de
l'indice composite) ou observed (35 actifs, collecte 15 min). covered_by_rules dit,
lui, lesquels peuvent produire un signal — et depuis le 24/08/2026 les deux ne se
confondent plus : un actif observed peut porter une règle sans entrer dans l'indice.
⚠️ Lire covered_by_rules, jamais tier, pour savoir d'où un signal peut venir.
display (depuis le 27/08/2026) dit ce qui est licencié pour l'affichage : full
(prix complet), derived — pour ces actifs, la source du niveau de prix n'est pas
licenciée pour la redistribution, donc seuls les dérivés irréversibles sont servis
(variation 24 h, direction, RSI — ni niveau, ni historique de niveaux) —, none
(depuis le 30/08/2026 : aucune donnée de marché servie, l'actif est absent de
/prices et son historique répond 403), ou iex (depuis le 31/08/2026 : les prix
servis sont le relevé quotidien « IEX Delayed » — dernier échange de la séance
régulière enregistré sur la bourse IEX, publié le lendemain (J+1), horodaté au dernier
échange réel ; ce n'est pas la clôture officielle. Data provided for free by
IEX — cette
attribution accompagne toute redistribution de ces valeurs).
GET /prices — dernier prix de tous les actifs
Renvoie prix, variation 24 h et horodatage pour tous les actifs. Réponse mise en cache
10 secondes (donc toujours plus fraîche que la collecte). ⚠️ Pour un actif
display: "derived", l'objet ne porte pas de champ price — seulement
change24h, timestamp et derived: true. Pour un actif display: "iex", l'objet
porte iex: true : prix et variation sont ceux du relevé quotidien IEX (J+1), la
variation est séance sur séance.
GET /prices/:asset — historique d'un actif
Paramètre days (1-365, défaut 30). ⚠️ Pour un actif display: "derived" ou
display: "none", la route répond 403 price_display_restricted : un historique de
niveaux permettrait de reconstituer la série source. Pour un actif display: "iex",
l'historique servi est celui des relevés quotidiens IEX (source: "iex" dans la
réponse — série démarrée le 24/08/2026, elle s'allonge chaque nuit).
curl -H "X-API-Key: $KEY" "https://geo-pulse.app/api/v1/prices/VIX?days=90"
Un symbole inconnu renvoie 404 avec la liste des symboles connus — pas besoin
d'aller la chercher ailleurs.
GET /events — événements géopolitiques scorés
Paramètre limit (1-200, défaut 20). Chaque événement porte son score de sévérité
(0-10, issu du scoring IA), sa catégorie, sa région et sa source.
GET /signals — signaux ouverts
Les décisions non encore résolues : règle, actif, direction, magnitude attendue, horizon, confiance, prix à l'émission, date de résolution prévue.
Ce sont des signaux algorithmiques, pas des conseils en investissement. La méthode, les abstentions et le track record scellé sont publics sur geo-pulse.app/scoreboard.
GET /index — indice composite GeoPulse
Score 0-100 et ses cinq sous-scores (géopolitique, sentiment, stress, momentum,
volatilité). Paramètre history (1-500) pour la série.
{ "index": { "score": 62, "classification": "elevated",
"components": { "geo": 71, "sentiment": 48, "stress": 55,
"momentum": 75, "volatility": 60 },
"calculated_at": 1784800000000 } }
GET /correlations — corrélations entre actifs
Pearson sur 30 jours glissants, recalculé toutes les 15 minutes.
GET /usage — votre consommation
Paramètre days (1-90, défaut 30). Renvoie la consommation du jour et l'historique
quotidien de la clé utilisée pour l'appel.
Codes de réponse
| code | signification | que faire |
|---|---|---|
200 |
Succès | — |
401 api_key_required |
Aucune clé fournie | Ajoutez l'en-tête |
401 api_key_invalid |
Clé inconnue | Vérifiez la clé ; elle a peut-être été régénérée |
401 api_key_revoked |
Clé révoquée | Créez-en une nouvelle depuis votre compte |
403 api_plan_required |
Le compte n'est plus sur le plan API | Réactivez l'abonnement |
404 unknown_asset |
Symbole inconnu | La réponse liste les symboles valides |
429 rate_limit_exceeded |
Débit dépassé | Attendez Retry-After secondes |
429 quota_exceeded |
Quota journalier atteint | Attendez 00:00 UTC |
Le tier du compte est relu à chaque requête : une résiliation coupe l'accès immédiatement, sans qu'il faille révoquer les clés une par une.
Exemple complet
export KEY="gp_live_votrecle"
BASE="https://geo-pulse.app/api/v1"
# Indice composite et ses composantes
curl -s -H "X-API-Key: $KEY" "$BASE/index" | jq '.index'
# Les 5 événements les plus récents, avec leur score de sévérité
curl -s -H "X-API-Key: $KEY" "$BASE/events?limit=5" | jq '.events[] | {title, score}'
# Historique de l'or sur 90 jours
curl -s -H "X-API-Key: $KEY" "$BASE/prices/XAU?days=90" | jq '.count'
# Consommation restante
curl -sD- -o/dev/null -H "X-API-Key: $KEY" "$BASE/prices" | grep -i ratelimit
Stabilité et versionnage
La v1 est additive : de nouveaux champs peuvent apparaître, aucun champ existant ne sera retiré ni renommé sans une v2. Écrivez vos clients en ignorant les champs inconnus.
Les réponses sont normalisées et ne reflètent pas le schéma interne de la base : nos tables peuvent évoluer sans casser votre intégration.
Nous ne publions pas d'engagement de disponibilité (SLA). L'infrastructure est un serveur unique ; annoncer 99,9 % serait un chiffre que nous ne pouvons pas encore tenir.
Webhooks
Plutôt que d'interroger l'API en boucle, faites-vous prévenir. Les endpoints se configurent depuis votre compte → onglet API.
Événements disponibles : signal.created, signal.resolved,
event.high_severity, index.updated.
Ce que vous recevez
POST https://votre-domaine/hook
Content-Type: application/json
X-GeoPulse-Event: signal.created
X-GeoPulse-Timestamp: 1784800000
X-GeoPulse-Signature: sha256=<hmac>
X-GeoPulse-Delivery: 4213
{ "type": "signal.created", "created_at": 1784800000000, "data": { … } }
Vérifier la signature — à faire systématiquement
La signature est un HMAC-SHA256 de <timestamp>.<corps exact reçu>, avec le secret
affiché à la création de l'endpoint.
import crypto from 'node:crypto';
function verify(rawBody, headers, secret) {
const ts = headers['x-geopulse-timestamp'];
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const got = (headers['x-geopulse-signature'] || '').replace('sha256=', '');
// Comparaison à temps constant : une comparaison naïve fuit la signature.
const ok = got.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
// L'horodatage fait partie de la signature : refusez ce qui est trop vieux,
// sinon un appel intercepté peut être rejoué indéfiniment.
return ok && Math.abs(Date.now() / 1000 - Number(ts)) < 300;
}
⚠️ Signez le corps brut, avant tout JSON.parse. Une re-sérialisation change les
espaces et invalide la signature.
Livraison et nouvelles tentatives
Une réponse 2xx vaut accusé de réception. Tout le reste — code d'erreur, délai
dépassé (10 s), connexion refusée — déclenche une nouvelle tentative selon un délai
croissant : 1 min, 5 min, 15 min, 1 h, 6 h, 24 h, puis abandon de cet événement.
Après 10 échecs consécutifs, l'endpoint est désactivé et cesse de recevoir. Le journal reste consultable, et vous pouvez le réactiver après correction.
Répondez vite (< 10 s) : mettez le traitement en file de votre côté plutôt que de le faire pendant la requête.
Contraintes
HTTPS obligatoire, adresses internes refusées, 5 endpoints actifs maximum. Le secret n'est affiché qu'à la création — il se régénère, il ne se relit pas. Le journal des livraisons est conservé 30 jours.