12 KiB
API Reference
Base URL : http://localhost:8080
Toutes les réponses sont en application/json. Les erreurs retournent {"error": "message"}.
Authentification
Toutes les routes (sauf GET /health) requièrent le header :
X-Owner-ID: <integer>
En dev, c'est l'ID numérique de l'owner. Les comptes, transactions et snapshots sont strictement filtrés par owner — un owner ne peut ni voir ni modifier les ressources d'un autre.
Réponse 401 — header absent ou invalide
{ "error": "missing X-Owner-ID header" }
À remplacer par JWT en production.
Health
GET /health
Vérifie la disponibilité du serveur et de la base de données.
Réponse 200
{ "status": "ok" }
Réponse 503 — base indisponible
Instruments
Un instrument représente tout actif coté : devise (EUR), action, ETF, crypto. Le prix EUR vaut toujours 1 et est inséré automatiquement au démarrage.
GET /instruments
Liste tous les instruments.
Réponse 200
[
{ "id": 1, "type": "devise", "code": "EUR", "name": "Euro", "devise_cotation": "EUR" },
{ "id": 2, "type": "etf", "code": "LU1681043599", "name": "Amundi MSCI World", "devise_cotation": "EUR" }
]
GET /instruments/{id}
Réponse 200
{ "id": 2, "type": "etf", "code": "LU1681043599", "name": "Amundi MSCI World", "devise_cotation": "EUR" }
Réponse 404 — instrument introuvable
POST /instruments
Corps
| Champ | Type | Requis | Description |
|---|---|---|---|
type |
string | ✅ | devise, action, etf, crypto |
code |
string | ✅ | ISIN (actions/ETF), ticker (crypto), code devise |
name |
string | ✅ | Nom lisible |
devise_cotation |
string | Devise de cotation (défaut : EUR) |
Réponse 201
{ "id": 3, "type": "crypto", "code": "BTC", "name": "Bitcoin", "devise_cotation": "EUR" }
Pipeline de prix : le ticker Yahoo Finance (actions/ETF) est résolu automatiquement via OpenFIGI au prochain cycle. L'ID CoinGecko (crypto) est résolu via l'API search CoinGecko. Les résolutions sont mises en cache dans
instrument_ticker_cache.
PUT /instruments/{id}
Même corps que POST. Retourne l'instrument mis à jour.
DELETE /instruments/{id}
Réponse 204 — supprimé
Comptes
Un compte est un conteneur de positions. Son solde est entièrement dérivé des transactions (aucun solde stocké).
Les enveloppes sont des sous-comptes monétaires liés à un compte maître (voir section Enveloppes).
GET /accounts/{id} retourne toujours le compte avec sa liste d'enveloppes.
GET /accounts
Liste les comptes maîtres (sans les enveloppes).
Réponse 200
[
{
"id": 1,
"nom": "Livret A",
"type": "livret",
"devise_reference": "EUR",
"plafond": 22950
}
]
GET /accounts/{id}
Retourne le compte et ses enveloppes.
Réponse 200
{
"id": 1,
"nom": "Livret A",
"type": "livret",
"devise_reference": "EUR",
"plafond": 22950,
"envelopes": [
{
"id": 3,
"nom": "Vacances",
"type": "livret",
"devise_reference": "EUR",
"master_account_id": 1,
"objectif": "Road trip USA"
}
]
}
Réponse 404 — compte introuvable
POST /accounts
Crée un compte maître.
Corps
| Champ | Type | Requis | Description |
|---|---|---|---|
nom |
string | ✅ | Nom du compte |
type |
string | ✅ | courant, livret, pea, cto, crypto, ... |
devise_reference |
string | Devise de référence (défaut : EUR) |
|
plafond |
number | Plafond réglementaire (indicatif) |
Réponse 201
{ "id": 1, "nom": "Livret A", "type": "livret", "devise_reference": "EUR", "plafond": 22950 }
PUT /accounts/{id}
Met à jour un compte maître. Même corps que POST.
DELETE /accounts/{id}
Supprime le compte et toutes ses enveloppes (CASCADE).
Réponse 204
Enveloppes
Une enveloppe est un sous-compte monétaire rattaché à un compte maître. Elle hérite automatiquement du type et de la devise_reference de son maître. Le solde est dérivé des transactions, comme pour tout compte.
Règles :
- Un compte maître ne peut pas lui-même être une enveloppe (pas de chaînage)
- Supprimée automatiquement avec son compte maître
GET /accounts/{id}/envelopes
Liste les enveloppes d'un compte.
Réponse 200
[
{
"id": 3,
"nom": "Vacances",
"type": "livret",
"devise_reference": "EUR",
"master_account_id": 1,
"objectif": "Road trip USA"
}
]
POST /accounts/{id}/envelopes
Crée une enveloppe sous le compte {id}.
Corps
| Champ | Type | Requis | Description |
|---|---|---|---|
nom |
string | ✅ | Nom de l'enveloppe |
objectif |
string | Description libre de l'objectif |
Réponse 201
{
"id": 3,
"nom": "Vacances",
"type": "livret",
"devise_reference": "EUR",
"master_account_id": 1,
"objectif": "Road trip USA"
}
Réponse 400 — le compte est lui-même une enveloppe (chaînage interdit)
Réponse 404 — compte introuvable
PUT /envelopes/{id}
Met à jour le nom et/ou l'objectif d'une enveloppe.
Corps
| Champ | Type | Requis | Description |
|---|---|---|---|
nom |
string | ✅ | Nouveau nom |
objectif |
string | Nouvel objectif |
Réponse 200 — enveloppe mise à jour
Réponse 404 — enveloppe introuvable
DELETE /envelopes/{id}
Supprime l'enveloppe.
Réponse 204
Transactions
Une transaction est un échange atomique entre deux participants (comptes ou enveloppes) via des instruments. Chaque côté (source, dest) est soit entièrement renseigné soit entièrement null. Au moins un côté doit exister.
Cas couverts :
| Cas | Source | Dest |
|---|---|---|
| Flux entrant (salaire, dépôt) | null | compte + instrument + quantité |
| Flux sortant (dépense) | compte + instrument + quantité | null |
| Virement / allocation enveloppe | compte + instrument + quantité | compte + instrument + quantité |
| Achat de titres | compte, EUR, montant | compte, ETF, nb parts |
| Swap crypto | wallet, BTC, qté | wallet, ETH, qté |
Le champ validated indique si la transaction est réelle (true) ou prévisionnelle (false).
Les transactions non validées à date dépassée remontent dans ?pending=true (liste "à traiter").
GET /accounts/{id}/transactions
Vue centrée sur le compte : le montant est signé (positif = crédit, négatif = débit).
instrument_id est celui du côté du compte concerné.
contrepartie_account_id est le compte en face (null si flux externe).
Paramètres de filtre
| Paramètre | Type | Description |
|---|---|---|
validated |
boolean | true ou false |
pending |
boolean | true → non validées avec date ≤ aujourd'hui |
from |
string | Date de début YYYY-MM-DD |
to |
string | Date de fin YYYY-MM-DD |
Réponse 200 — triée par date DESC
[
{
"id": 1,
"date": "2026-06-13",
"montant": 2800.00,
"instrument_id": 1,
"tiers": "Employeur",
"label": "Salaire juin",
"categorie": "salaire",
"validated": true
},
{
"id": 2,
"date": "2026-06-10",
"montant": -50.00,
"instrument_id": 1,
"label": "Courses",
"categorie": "alimentation",
"validated": true
}
]
GET /transactions/{id}
Retourne la transaction brute (tous les champs source/dest).
Réponse 200
{
"id": 1,
"date": "2026-06-13",
"account_dest_id": 1,
"instrument_dest_id": 1,
"quantite_dest": 2800,
"tiers": "Employeur",
"label": "Salaire juin",
"categorie": "salaire",
"validated": true
}
Réponse 404 — introuvable
POST /transactions
Corps
| Champ | Type | Requis | Description |
|---|---|---|---|
date |
string | ✅ | YYYY-MM-DD |
label |
string | ✅ | Libellé |
validated |
boolean | Défaut false |
|
account_source_id |
integer | Compte source | |
instrument_source_id |
integer | Instrument source | |
quantite_source |
number | Quantité source | |
account_dest_id |
integer | Compte dest | |
instrument_dest_id |
integer | Instrument dest | |
quantite_dest |
number | Quantité dest | |
tiers |
string | Tiers externe (employeur, commerçant…) | |
categorie |
string | Catégorie libre |
Les trois champs de chaque côté (account, instrument, quantite) doivent être tous renseignés ou tous null.
Réponse 201 — transaction créée (format brut)
Réponse 400 — body invalide, label manquant, date manquante, ou violation de la contrainte source/dest
PUT /transactions/{id}
Mise à jour complète. Même corps que POST.
Réponse 200 — transaction mise à jour (format brut)
Réponse 404 — introuvable
PATCH /transactions/{id}/validate
Valide ou dé-valide une transaction.
Corps
{ "validated": true }
Réponse 200 — transaction avec le nouveau statut
Réponse 404 — introuvable
DELETE /transactions/{id}
Réponse 204
Snapshots
Les snapshots capturent la valorisation de chaque compte sur une fenêtre glissante :
- Passé : transactions validées uniquement
- Futur : toutes les transactions (validées ou non) — projection basée sur les transactions planifiées
Deux tables sont alimentées :
position_snapshot— quantité + valeur par instrument et par compteaccount_snapshot— valeur totale agrégée par compte
Fenêtre : de la première transaction jusqu'à today + SNAPSHOT_HORIZON_DAYS (défaut : 30 jours). Configurable via la variable d'environnement SNAPSHOT_HORIZON_DAYS.
Toutes les transactions sont comptées quelle que soit leur validation.
Le snapshot représente toujours l'état envisagé complet du compte :
transactions confirmées (validated = true) et planifiées (validated = false).
La liste ?pending=true (transactions non validées à date dépassée) reste distincte — c'est un outil de suivi, pas un filtre de calcul.
Job daily-snapshot (toutes les 24h) :
- Traite les invalidations en attente
- Recalcule hier (consolide les transactions de la veille)
- Calcule le nouveau jour entrant dans la fenêtre (
today + horizon)
GET /accounts/{id}/snapshots
Liste la valorisation totale du compte jour par jour.
Paramètres de filtre
| Paramètre | Type | Description |
|---|---|---|
from |
string | Date de début YYYY-MM-DD (optionnel, défaut : première date disponible) |
to |
string | Date de fin YYYY-MM-DD (optionnel, défaut : dernier jour calculé dans la fenêtre) |
Réponse 200 — triée par date ASC
[
{ "date": "2026-06-01", "valeur": 2750.00 },
{ "date": "2026-06-02", "valeur": 2800.00 },
{ "date": "2026-07-13", "valeur": 2950.00 }
]
GET /accounts/{id}/snapshots/positions
Liste les positions détaillées (par instrument) du compte jour par jour.
Paramètres de filtre — mêmes que /snapshots (from, to)
Réponse 200 — triée par date ASC puis instrument_id
[
{
"date": "2026-06-01",
"instrument_id": 1,
"quantite": 2750.00,
"prix_cloture": 1.0,
"valeur": 2750.00
},
{
"date": "2026-06-01",
"instrument_id": 2,
"quantite": 5.0,
"pru": 350.00,
"prix_cloture": 360.00,
"valeur": 1800.00
}
]
POST /accounts/{id}/snapshots/recompute
Recalcule immédiatement les snapshots d'un compte depuis sa date d'invalidation jusqu'à today + horizon.
Chaque mutation de transaction (create, update, delete, validate/dévalider) marque automatiquement les comptes concernés comme dirty avec recompute_from = MIN(date_existante, date_transaction). Cet endpoint consomme ce flag sans attendre le job nocturne.
Réponse 200 — recalcul effectué
{ "account_id": 1, "from": "2026-06-01", "to": "2026-07-13", "status": "ok" }
Réponse 204 — aucune invalidation en attente, rien à faire
Réponse 404 — compte introuvable