@reqvet-sdk/sdk 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -65
- package/SDK_REFERENCE.md +176 -176
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
# @reqvet/sdk
|
|
1
|
+
# @reqvet-sdk/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SDK JavaScript/TypeScript officiel pour l'API [ReqVet](https://reqvet.com) — génération de comptes rendus vétérinaires par IA à partir d'enregistrements audio.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@reqvet/sdk)
|
|
5
|
+
[](https://www.npmjs.com/package/@reqvet-sdk/sdk)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Fonctionnalités
|
|
10
10
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
11
|
+
- **Uploader** un enregistrement audio (`uploadAudio`)
|
|
12
|
+
- **Générer** un compte rendu vétérinaire (`createJob`, `generateReport`)
|
|
13
|
+
- **Suivre** les jobs — via webhook ou polling (`getJob`, `waitForJob`, `listJobs`)
|
|
14
|
+
- **Amender** un compte rendu terminé avec un audio complémentaire (`amendJob`)
|
|
15
|
+
- **Régénérer** avec de nouvelles instructions (`regenerateJob`)
|
|
16
|
+
- **Reformuler** pour une audience spécifique — propriétaire, référé, spécialiste (`reformulateReport`)
|
|
17
|
+
- **Gérer les templates** (`listTemplates`, `createTemplate`, `updateTemplate`, `deleteTemplate`)
|
|
18
|
+
- **Vérifier les webhooks** avec HMAC (`@reqvet-sdk/sdk/webhooks`)
|
|
19
19
|
|
|
20
|
-
> **Note
|
|
20
|
+
> **Note** : ce SDK n'inclut pas d'enregistreur audio. Votre application gère l'enregistrement et passe un `File`, `Blob` ou `Buffer` au SDK.
|
|
21
21
|
|
|
22
22
|
## Installation
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npm install @reqvet/sdk
|
|
25
|
+
npm install @reqvet-sdk/sdk
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Nécessite Node.js ≥ 18. Fonctionne dans les navigateurs modernes pour les méthodes client (Blob/FormData requis pour l'upload).
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Avant votre premier appel
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Votre responsable de compte ReqVet vous fournira trois variables d'environnement :
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
REQVET_API_KEY=rqv_live_...
|
|
36
36
|
REQVET_BASE_URL=https://api.reqvet.com
|
|
37
|
-
REQVET_WEBHOOK_SECRET=... #
|
|
37
|
+
REQVET_WEBHOOK_SECRET=... # uniquement si vous utilisez les webhooks
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Chaque job nécessite un `templateId`. **Appelez `listTemplates()` en premier** pour découvrir ce qui est disponible :
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
43
|
const { system, custom } = await reqvet.listTemplates();
|
|
44
|
-
// system = ReqVet
|
|
45
|
-
// custom = templates
|
|
44
|
+
// system = templates fournis par ReqVet, visibles par toutes les organisations (lecture seule)
|
|
45
|
+
// custom = templates créés par votre organisation
|
|
46
46
|
|
|
47
47
|
const templateId = system[0].id;
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## Démarrage rapide
|
|
51
51
|
|
|
52
|
-
###
|
|
52
|
+
### Flux webhook (recommandé)
|
|
53
53
|
|
|
54
54
|
```ts
|
|
55
|
-
import ReqVet from '@reqvet/sdk';
|
|
55
|
+
import ReqVet from '@reqvet-sdk/sdk';
|
|
56
56
|
|
|
57
57
|
const reqvet = new ReqVet(process.env.REQVET_API_KEY!, {
|
|
58
58
|
baseUrl: process.env.REQVET_BASE_URL,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
// 1.
|
|
61
|
+
// 1. Uploader l'audio
|
|
62
62
|
const { path } = await reqvet.uploadAudio(audioBuffer, 'consultation.webm');
|
|
63
63
|
|
|
64
|
-
// 2.
|
|
64
|
+
// 2. Créer un job — ReqVet POSTera le résultat sur votre webhook quand il sera prêt
|
|
65
65
|
const job = await reqvet.createJob({
|
|
66
66
|
audioFile: path,
|
|
67
67
|
animalName: 'Rex',
|
|
68
68
|
templateId: 'your-template-uuid',
|
|
69
69
|
callbackUrl: 'https://your-app.com/api/reqvet/webhook',
|
|
70
|
-
metadata: { consultationId: 'abc123' }, //
|
|
70
|
+
metadata: { consultationId: 'abc123' }, // transmis tel quel à votre webhook
|
|
71
71
|
});
|
|
72
72
|
// { job_id: '...', status: 'pending' }
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
Votre webhook reçoit un événement `job.completed` :
|
|
76
76
|
|
|
77
77
|
```json
|
|
78
78
|
{
|
|
@@ -86,7 +86,7 @@ Your webhook receives a `job.completed` event:
|
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
###
|
|
89
|
+
### Flux polling (plus simple pour le développement)
|
|
90
90
|
|
|
91
91
|
```ts
|
|
92
92
|
const report = await reqvet.generateReport({
|
|
@@ -99,10 +99,10 @@ const report = await reqvet.generateReport({
|
|
|
99
99
|
// { jobId, html, fields, transcription, cost, metadata }
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
###
|
|
102
|
+
### Vérifier un webhook entrant
|
|
103
103
|
|
|
104
104
|
```ts
|
|
105
|
-
import { verifyWebhookSignature } from '@reqvet/sdk/webhooks';
|
|
105
|
+
import { verifyWebhookSignature } from '@reqvet-sdk/sdk/webhooks';
|
|
106
106
|
|
|
107
107
|
export async function POST(req: NextRequest) {
|
|
108
108
|
const rawBody = await req.text();
|
|
@@ -123,36 +123,36 @@ export async function POST(req: NextRequest) {
|
|
|
123
123
|
|
|
124
124
|
## API
|
|
125
125
|
|
|
126
|
-
|
|
|
127
|
-
|
|
128
|
-
| `uploadAudio(audio, fileName?)` |
|
|
129
|
-
| `generateReport(params)` | Upload +
|
|
130
|
-
| `createJob(params)` |
|
|
131
|
-
| `listJobs(options?)` |
|
|
132
|
-
| `getJob(jobId)` |
|
|
133
|
-
| `waitForJob(jobId, onStatus?)` |
|
|
134
|
-
| `regenerateJob(jobId, options?)` |
|
|
135
|
-
| `amendJob(jobId, params)` |
|
|
136
|
-
| `reformulateReport(jobId, params)` |
|
|
137
|
-
| `listReformulations(jobId)` |
|
|
138
|
-
| `listTemplates()` |
|
|
139
|
-
| `getTemplate(templateId)` |
|
|
140
|
-
| `createTemplate(params)` |
|
|
141
|
-
| `updateTemplate(templateId, updates)` |
|
|
142
|
-
| `deleteTemplate(templateId)` |
|
|
143
|
-
| `health()` |
|
|
144
|
-
|
|
145
|
-
##
|
|
146
|
-
|
|
147
|
-
ReqVet
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
126
|
+
| Méthode | Description |
|
|
127
|
+
|---------|-------------|
|
|
128
|
+
| `uploadAudio(audio, fileName?)` | Uploader un fichier audio |
|
|
129
|
+
| `generateReport(params)` | Upload + création de job (helper tout-en-un) |
|
|
130
|
+
| `createJob(params)` | Créer un job de génération |
|
|
131
|
+
| `listJobs(options?)` | Lister les jobs avec pagination et filtre par statut |
|
|
132
|
+
| `getJob(jobId)` | Obtenir le statut et le résultat d'un job |
|
|
133
|
+
| `waitForJob(jobId, onStatus?)` | Attendre en polling la fin d'un job |
|
|
134
|
+
| `regenerateJob(jobId, options?)` | Régénérer un compte rendu terminé |
|
|
135
|
+
| `amendJob(jobId, params)` | Ajouter un audio complémentaire à un job terminé |
|
|
136
|
+
| `reformulateReport(jobId, params)` | Générer une version adaptée à une audience |
|
|
137
|
+
| `listReformulations(jobId)` | Lister toutes les reformulations d'un job |
|
|
138
|
+
| `listTemplates()` | Lister les templates disponibles (`{ system, custom }`) |
|
|
139
|
+
| `getTemplate(templateId)` | Obtenir un template par son ID |
|
|
140
|
+
| `createTemplate(params)` | Créer un template personnalisé |
|
|
141
|
+
| `updateTemplate(templateId, updates)` | Mettre à jour un template |
|
|
142
|
+
| `deleteTemplate(templateId)` | Supprimer un template |
|
|
143
|
+
| `health()` | Vérification de l'état de l'API |
|
|
144
|
+
|
|
145
|
+
## Événements webhook
|
|
146
|
+
|
|
147
|
+
ReqVet déclenche 5 types d'événements : `job.completed`, `job.failed`, `job.amended`, `job.amend_failed`, `job.regenerated`.
|
|
148
|
+
|
|
149
|
+
Les livraisons échouées sont retentées 3 fois (0s, 2s, 5s). Implémentez l'idempotence dans votre handler — dédoublonnez sur `job_id + event`.
|
|
150
|
+
|
|
151
|
+
Voir [SDK_REFERENCE.md §6](./SDK_REFERENCE.md#6-webhook-events) pour la structure complète des payloads de chaque événement.
|
|
152
152
|
|
|
153
153
|
## TypeScript
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
Définitions TypeScript complètes incluses :
|
|
156
156
|
|
|
157
157
|
```ts
|
|
158
158
|
import type {
|
|
@@ -162,18 +162,18 @@ import type {
|
|
|
162
162
|
Template,
|
|
163
163
|
ReqVetReformulation,
|
|
164
164
|
ExtractedFields,
|
|
165
|
-
} from '@reqvet/sdk';
|
|
165
|
+
} from '@reqvet-sdk/sdk';
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
##
|
|
168
|
+
## Pour aller plus loin
|
|
169
169
|
|
|
170
|
-
- [SDK_REFERENCE.md](./SDK_REFERENCE.md) —
|
|
171
|
-
- [SECURITY.md](./SECURITY.md) —
|
|
170
|
+
- [SDK_REFERENCE.md](./SDK_REFERENCE.md) — documentation complète des paramètres et réponses, tous les payloads webhook, schéma des champs, codes d'erreur
|
|
171
|
+
- [SECURITY.md](./SECURITY.md) — bonnes pratiques de sécurité, pattern proxy, exemple complet de vérification webhook
|
|
172
172
|
|
|
173
|
-
##
|
|
173
|
+
## Sécurité
|
|
174
174
|
|
|
175
|
-
**
|
|
175
|
+
**Ne jamais** exposer votre clé API dans du code côté client. Utilisez toujours le SDK côté serveur et proxifiez les requêtes depuis votre frontend. Voir [SECURITY.md](./SECURITY.md).
|
|
176
176
|
|
|
177
|
-
##
|
|
177
|
+
## Licence
|
|
178
178
|
|
|
179
179
|
MIT
|
package/SDK_REFERENCE.md
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
# @reqvet/sdk —
|
|
1
|
+
# @reqvet-sdk/sdk — Référence technique
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Documentation complète des paramètres et réponses pour toutes les méthodes du SDK.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## 1)
|
|
7
|
+
## 1) Instanciation
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import ReqVet from '@reqvet/sdk';
|
|
10
|
+
import ReqVet from '@reqvet-sdk/sdk';
|
|
11
11
|
|
|
12
12
|
const reqvet = new ReqVet(process.env.REQVET_API_KEY!, {
|
|
13
13
|
baseUrl: process.env.REQVET_BASE_URL ?? 'https://api.reqvet.com',
|
|
14
|
-
pollInterval: 5000, // polling
|
|
15
|
-
timeout: 5 * 60 * 1000, //
|
|
14
|
+
pollInterval: 5000, // intervalle de polling en ms (défaut : 5000)
|
|
15
|
+
timeout: 5 * 60 * 1000, // attente maximale en polling en ms (défaut : 300 000 = 5 min)
|
|
16
16
|
});
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
La clé API doit commencer par `rqv_`. Une `Error` est levée immédiatement dans le cas contraire.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## 2)
|
|
23
|
+
## 2) Avant votre premier appel
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### Obtenir vos identifiants
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
- `REQVET_API_KEY` —
|
|
29
|
-
- `REQVET_BASE_URL` —
|
|
30
|
-
- `REQVET_WEBHOOK_SECRET` —
|
|
27
|
+
Votre responsable de compte ReqVet vous fournira :
|
|
28
|
+
- `REQVET_API_KEY` — votre clé API d'organisation (`rqv_live_...`)
|
|
29
|
+
- `REQVET_BASE_URL` — l'URL de base de l'API
|
|
30
|
+
- `REQVET_WEBHOOK_SECRET` — votre secret de signature webhook (si vous utilisez les webhooks)
|
|
31
31
|
|
|
32
|
-
###
|
|
32
|
+
### Découvrir vos templates
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Chaque job nécessite un `templateId`. Avant de générer des comptes rendus, listez les templates disponibles pour votre organisation :
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
37
|
const { custom, system } = await reqvet.listTemplates();
|
|
38
|
-
// system = templates
|
|
39
|
-
// custom = templates
|
|
40
|
-
const templateId = system[0].id; //
|
|
38
|
+
// system = templates créés par ReqVet, disponibles pour toutes les organisations (lecture seule)
|
|
39
|
+
// custom = templates créés par votre organisation
|
|
40
|
+
const templateId = system[0].id; // ou custom[0].id
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
-
## 3)
|
|
45
|
+
## 3) Patterns d'intégration
|
|
46
46
|
|
|
47
|
-
### A) Webhook
|
|
47
|
+
### A) Webhook en priorité (recommandé pour la production)
|
|
48
48
|
|
|
49
49
|
```
|
|
50
|
-
uploadAudio() → createJob({ callbackUrl }) → ReqVet
|
|
50
|
+
uploadAudio() → createJob({ callbackUrl }) → ReqVet POSTe le résultat sur votre endpoint
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
L'utilisateur peut fermer le navigateur — le résultat arrive sur votre serveur de manière asynchrone.
|
|
54
54
|
|
|
55
|
-
### B) Polling (
|
|
55
|
+
### B) Polling (développement / intégrations simples)
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
uploadAudio() → createJob() → waitForJob() →
|
|
58
|
+
uploadAudio() → createJob() → waitForJob() → rapport
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
Ou utilisez le wrapper pratique :
|
|
62
62
|
|
|
63
63
|
```ts
|
|
64
64
|
const report = await reqvet.generateReport({ audio, animalName, templateId, waitForResult: true });
|
|
@@ -66,92 +66,92 @@ const report = await reqvet.generateReport({ audio, animalName, templateId, wait
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
-
## 4)
|
|
69
|
+
## 4) Méthodes
|
|
70
70
|
|
|
71
71
|
### `uploadAudio(audio, fileName?)`
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Uploader un fichier audio vers le stockage ReqVet.
|
|
74
74
|
|
|
75
|
-
**
|
|
76
|
-
|
|
|
77
|
-
|
|
78
|
-
| `audio` | `Blob \| File \| Buffer` | ✅ |
|
|
79
|
-
| `fileName` | `string` | — |
|
|
75
|
+
**Paramètres :**
|
|
76
|
+
| Nom | Type | Requis | Description |
|
|
77
|
+
|-----|------|--------|-------------|
|
|
78
|
+
| `audio` | `Blob \| File \| Buffer` | ✅ | Données audio |
|
|
79
|
+
| `fileName` | `string` | — | Nom du fichier, utilisé pour inférer le type MIME (défaut : `audio.webm`) |
|
|
80
80
|
|
|
81
|
-
**
|
|
81
|
+
**Réponse :**
|
|
82
82
|
```ts
|
|
83
83
|
{
|
|
84
|
-
audio_file: string; //
|
|
85
|
-
path: string; // alias
|
|
84
|
+
audio_file: string; // chemin de stockage canonique — à passer à createJob()
|
|
85
|
+
path: string; // alias de audio_file
|
|
86
86
|
size_bytes: number;
|
|
87
87
|
content_type: string;
|
|
88
88
|
}
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Formats supportés : `mp3`, `wav`, `webm`, `ogg`, `m4a`, `aac`, `flac`. Taille max : 100 Mo.
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
95
95
|
### `generateReport(params)`
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
**
|
|
100
|
-
|
|
|
101
|
-
|
|
102
|
-
| `audio` | `Blob \| File \| Buffer` | ✅ |
|
|
103
|
-
| `animalName` | `string` | ✅ |
|
|
104
|
-
| `templateId` | `string` | ✅ |
|
|
105
|
-
| `fileName` | `string` | — |
|
|
106
|
-
| `callbackUrl` | `string` | — |
|
|
107
|
-
| `metadata` | `Record<string, unknown>` | — |
|
|
108
|
-
| `extraInstructions` | `string` | — |
|
|
109
|
-
| `waitForResult` | `boolean` | — |
|
|
110
|
-
| `onStatus` | `(status: string) => void` | — |
|
|
111
|
-
|
|
112
|
-
**
|
|
113
|
-
- `waitForResult: false` (
|
|
114
|
-
- `waitForResult: true
|
|
97
|
+
Wrapper pratique : `uploadAudio → createJob`. Attend optionnellement la fin du traitement.
|
|
98
|
+
|
|
99
|
+
**Paramètres :**
|
|
100
|
+
| Nom | Type | Requis | Description |
|
|
101
|
+
|-----|------|--------|-------------|
|
|
102
|
+
| `audio` | `Blob \| File \| Buffer` | ✅ | Données audio |
|
|
103
|
+
| `animalName` | `string` | ✅ | Nom de l'animal |
|
|
104
|
+
| `templateId` | `string` | ✅ | UUID du template (depuis `listTemplates()`) |
|
|
105
|
+
| `fileName` | `string` | — | Nom du fichier |
|
|
106
|
+
| `callbackUrl` | `string` | — | Votre endpoint webhook (HTTPS, accessible publiquement) |
|
|
107
|
+
| `metadata` | `Record<string, unknown>` | — | Données passthrough (ex. `{ consultationId, vetId }`) |
|
|
108
|
+
| `extraInstructions` | `string` | — | Instructions de génération supplémentaires injectées dans le prompt |
|
|
109
|
+
| `waitForResult` | `boolean` | — | Si `true`, poll et retourne le rapport final. Défaut : `false` |
|
|
110
|
+
| `onStatus` | `(status: string) => void` | — | Appelé à chaque poll (uniquement si `waitForResult: true`) |
|
|
111
|
+
|
|
112
|
+
**Réponse :**
|
|
113
|
+
- `waitForResult: false` (défaut) : `{ job_id: string, status: 'pending' }`
|
|
114
|
+
- `waitForResult: true` : `ReqVetReport` (voir `waitForJob`)
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
118
|
### `createJob(params)`
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Démarrer un pipeline de transcription + génération de compte rendu.
|
|
121
121
|
|
|
122
|
-
**
|
|
123
|
-
|
|
|
124
|
-
|
|
125
|
-
| `audioFile` | `string` | ✅ |
|
|
126
|
-
| `animalName` | `string` | ✅ |
|
|
127
|
-
| `templateId` | `string` | ✅ |
|
|
128
|
-
| `callbackUrl` | `string` | — |
|
|
129
|
-
| `metadata` | `Record<string, unknown>` | — |
|
|
130
|
-
| `extraInstructions` | `string` | — |
|
|
122
|
+
**Paramètres :**
|
|
123
|
+
| Nom | Type | Requis | Description |
|
|
124
|
+
|-----|------|--------|-------------|
|
|
125
|
+
| `audioFile` | `string` | ✅ | Valeur de `uploadAudio().path` |
|
|
126
|
+
| `animalName` | `string` | ✅ | Nom de l'animal |
|
|
127
|
+
| `templateId` | `string` | ✅ | UUID du template |
|
|
128
|
+
| `callbackUrl` | `string` | — | URL webhook (HTTPS, accessible publiquement). Utilise le webhook par défaut de l'organisation si omis. |
|
|
129
|
+
| `metadata` | `Record<string, unknown>` | — | Données passthrough — pour corréler avec vos propres enregistrements |
|
|
130
|
+
| `extraInstructions` | `string` | — | Instructions de génération supplémentaires (max 5 000 caractères) |
|
|
131
131
|
|
|
132
|
-
**
|
|
132
|
+
**Réponse :**
|
|
133
133
|
```ts
|
|
134
134
|
{ job_id: string; status: 'pending' }
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
> **
|
|
137
|
+
> **Limite de débit** : 10 000 requêtes/minute par organisation.
|
|
138
138
|
|
|
139
139
|
---
|
|
140
140
|
|
|
141
141
|
### `listJobs(options?)`
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
Lister les jobs de l'organisation authentifiée, avec pagination et filtrage.
|
|
144
144
|
|
|
145
|
-
**
|
|
146
|
-
|
|
|
147
|
-
|
|
148
|
-
| `limit` | `number` | `20` |
|
|
149
|
-
| `offset` | `number` | `0` |
|
|
150
|
-
| `status` | `string` | — |
|
|
151
|
-
| `sort` | `string` | `created_at` |
|
|
152
|
-
| `order` | `string` | `desc` | Direction: `asc`
|
|
145
|
+
**Paramètres :**
|
|
146
|
+
| Nom | Type | Défaut | Description |
|
|
147
|
+
|-----|------|--------|-------------|
|
|
148
|
+
| `limit` | `number` | `20` | Résultats par page (1–100) |
|
|
149
|
+
| `offset` | `number` | `0` | Décalage de pagination |
|
|
150
|
+
| `status` | `string` | — | Filtre : `pending` `transcribing` `generating` `completed` `failed` `amending` |
|
|
151
|
+
| `sort` | `string` | `created_at` | Champ de tri : `created_at` ou `updated_at` |
|
|
152
|
+
| `order` | `string` | `desc` | Direction : `asc` ou `desc` |
|
|
153
153
|
|
|
154
|
-
**
|
|
154
|
+
**Réponse :**
|
|
155
155
|
```ts
|
|
156
156
|
{
|
|
157
157
|
jobs: JobSummary[];
|
|
@@ -163,11 +163,11 @@ List jobs for the authenticated organization, with pagination and filtering.
|
|
|
163
163
|
|
|
164
164
|
### `getJob(jobId)`
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
Obtenir l'état actuel et le résultat d'un job.
|
|
167
167
|
|
|
168
|
-
**
|
|
168
|
+
**Champs de réponse par statut :**
|
|
169
169
|
|
|
170
|
-
|
|
|
170
|
+
| Champ | `pending` | `transcribing` | `generating` | `completed` | `failed` |
|
|
171
171
|
|-------|:---------:|:--------------:|:------------:|:-----------:|:--------:|
|
|
172
172
|
| `job_id` | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
173
173
|
| `status` | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
@@ -179,9 +179,9 @@ Get the current state and result of a job.
|
|
|
179
179
|
| `cost` | — | — | — | ✅ | — |
|
|
180
180
|
| `error` | — | — | — | — | ✅ |
|
|
181
181
|
|
|
182
|
-
*`result.fields`
|
|
182
|
+
*`result.fields` n'est présent que si votre organisation a un `field_schema` configuré (extraction de données structurées). Vaut `null` sinon. Voir [Schéma de champs](#5-schéma-de-champs) ci-dessous.
|
|
183
183
|
|
|
184
|
-
**
|
|
184
|
+
**Structure du coût (jobs terminés) :**
|
|
185
185
|
```ts
|
|
186
186
|
cost: {
|
|
187
187
|
transcription_usd: number;
|
|
@@ -190,20 +190,20 @@ cost: {
|
|
|
190
190
|
}
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
> **Note
|
|
193
|
+
> **Note** : `cost` est disponible via `getJob()` et `waitForJob()`, mais n'est **pas** inclus dans les payloads webhook. Récupérez-le avec `getJob()` après réception d'un événement `job.completed` si nécessaire.
|
|
194
194
|
|
|
195
195
|
---
|
|
196
196
|
|
|
197
197
|
### `waitForJob(jobId, onStatus?)`
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
Poller jusqu'à ce qu'un job atteigne `completed` ou `failed`. Respecte `pollInterval` et `timeout`.
|
|
200
200
|
|
|
201
|
-
**
|
|
201
|
+
**Réponse (`ReqVetReport`) :**
|
|
202
202
|
```ts
|
|
203
203
|
{
|
|
204
204
|
jobId: string;
|
|
205
|
-
html: string; //
|
|
206
|
-
fields: ExtractedFields | null; // null
|
|
205
|
+
html: string; // HTML du compte rendu généré
|
|
206
|
+
fields: ExtractedFields | null; // null si aucun field_schema configuré
|
|
207
207
|
transcription: string;
|
|
208
208
|
animalName: string;
|
|
209
209
|
cost: { transcription_usd: number; generation_usd: number; total_usd: number };
|
|
@@ -211,70 +211,70 @@ Poll until a job reaches `completed` or `failed`. Respects `pollInterval` and `t
|
|
|
211
211
|
}
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
Lève une `ReqVetError` si le job échoue ou si le timeout est dépassé.
|
|
215
215
|
|
|
216
216
|
---
|
|
217
217
|
|
|
218
218
|
### `regenerateJob(jobId, options?)`
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
Régénérer le compte rendu d'un job terminé — par exemple avec des instructions différentes ou un autre template.
|
|
221
221
|
|
|
222
|
-
**
|
|
223
|
-
|
|
|
224
|
-
|
|
225
|
-
| `extraInstructions` | `string` |
|
|
226
|
-
| `templateId` | `string` |
|
|
222
|
+
**Paramètres :**
|
|
223
|
+
| Nom | Type | Description |
|
|
224
|
+
|-----|------|-------------|
|
|
225
|
+
| `extraInstructions` | `string` | Nouvelles instructions (max 2 000 caractères) |
|
|
226
|
+
| `templateId` | `string` | Basculer vers un autre template |
|
|
227
227
|
|
|
228
|
-
**
|
|
228
|
+
**Réponse :**
|
|
229
229
|
```ts
|
|
230
230
|
{ job_id: string; status: 'completed'; result: { html: string; fields?: ExtractedFields } }
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
Déclenche un événement webhook `job.regenerated` si un `callbackUrl` est configuré.
|
|
234
234
|
|
|
235
|
-
> **
|
|
235
|
+
> **Limite de débit** : 30 requêtes/minute par organisation.
|
|
236
236
|
|
|
237
237
|
---
|
|
238
238
|
|
|
239
239
|
### `amendJob(jobId, params)`
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
Ajouter un audio complémentaire à un job terminé. Le nouvel audio est transcrit, fusionné avec la transcription existante, et le compte rendu est régénéré.
|
|
242
242
|
|
|
243
|
-
**
|
|
244
|
-
|
|
|
245
|
-
|
|
246
|
-
| `audioFile` | `string` | ✅ |
|
|
247
|
-
| `templateId` | `string` | — |
|
|
243
|
+
**Paramètres :**
|
|
244
|
+
| Nom | Type | Requis | Description |
|
|
245
|
+
|-----|------|--------|-------------|
|
|
246
|
+
| `audioFile` | `string` | ✅ | Valeur de `uploadAudio().path` |
|
|
247
|
+
| `templateId` | `string` | — | Basculer vers un autre template |
|
|
248
248
|
|
|
249
|
-
**
|
|
249
|
+
**Réponse :**
|
|
250
250
|
```ts
|
|
251
251
|
{ job_id: string; status: 'amending'; amendment_number: number; message: string }
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
Le job repasse à `completed` quand l'amendement est terminé. Utilisez `waitForJob()` ou écoutez l'événement webhook `job.amended`. Plusieurs amendements sont supportés — chacun est ajouté à la transcription complète.
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
258
258
|
### `reformulateReport(jobId, params)`
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
Générer une version alternative d'un compte rendu terminé pour une audience spécifique.
|
|
261
261
|
|
|
262
|
-
**
|
|
263
|
-
|
|
|
264
|
-
|
|
262
|
+
**Paramètres :**
|
|
263
|
+
| Nom | Type | Requis | Description |
|
|
264
|
+
|-----|------|--------|-------------|
|
|
265
265
|
| `purpose` | `string` | ✅ | `owner` `referral` `summary` `custom` `diagnostic_hypothesis` |
|
|
266
|
-
| `customInstructions` | `string` |
|
|
267
|
-
|
|
268
|
-
**
|
|
269
|
-
|
|
|
270
|
-
|
|
271
|
-
| `owner` |
|
|
272
|
-
| `referral` |
|
|
273
|
-
| `summary` |
|
|
274
|
-
| `diagnostic_hypothesis` |
|
|
275
|
-
| `custom` |
|
|
276
|
-
|
|
277
|
-
**
|
|
266
|
+
| `customInstructions` | `string` | Si `purpose: 'custom'` | Instructions de reformulation |
|
|
267
|
+
|
|
268
|
+
**Valeurs de `purpose` :**
|
|
269
|
+
| Valeur | Résultat |
|
|
270
|
+
|--------|----------|
|
|
271
|
+
| `owner` | Version simplifiée pour le propriétaire de l'animal |
|
|
272
|
+
| `referral` | Résumé clinique pour un spécialiste |
|
|
273
|
+
| `summary` | Note interne courte |
|
|
274
|
+
| `diagnostic_hypothesis` | Liste de diagnostics différentiels |
|
|
275
|
+
| `custom` | Défini par `customInstructions` |
|
|
276
|
+
|
|
277
|
+
**Réponse (`ReqVetReformulation`) :**
|
|
278
278
|
```ts
|
|
279
279
|
{
|
|
280
280
|
id: string;
|
|
@@ -287,13 +287,13 @@ Generate an alternative version of a completed report for a specific audience.
|
|
|
287
287
|
}
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
-
> **
|
|
290
|
+
> **Limite de débit** : 30 requêtes/minute par organisation.
|
|
291
291
|
|
|
292
292
|
---
|
|
293
293
|
|
|
294
294
|
### `listReformulations(jobId)`
|
|
295
295
|
|
|
296
|
-
**
|
|
296
|
+
**Réponse :** `{ reformulations: ReqVetReformulation[] }`
|
|
297
297
|
|
|
298
298
|
---
|
|
299
299
|
|
|
@@ -301,15 +301,15 @@ Generate an alternative version of a completed report for a specific audience.
|
|
|
301
301
|
|
|
302
302
|
#### `listTemplates()` → `{ custom: Template[], system: Template[] }`
|
|
303
303
|
|
|
304
|
-
- **`system`** — templates
|
|
305
|
-
- **`custom`** — templates
|
|
304
|
+
- **`system`** — templates créés par ReqVet, visibles par toutes les organisations. Lecture seule. Commencez ici pour trouver les `templateId` disponibles.
|
|
305
|
+
- **`custom`** — templates créés par votre organisation. Modifiables via `createTemplate` / `updateTemplate`.
|
|
306
306
|
|
|
307
307
|
#### `getTemplate(templateId)` → `Template`
|
|
308
308
|
|
|
309
309
|
#### `createTemplate(params)` → `Template`
|
|
310
310
|
|
|
311
|
-
|
|
|
312
|
-
|
|
311
|
+
| Nom | Type | Requis |
|
|
312
|
+
|-----|------|--------|
|
|
313
313
|
| `name` | `string` | ✅ |
|
|
314
314
|
| `content` | `string` | ✅ |
|
|
315
315
|
| `description` | `string` | — |
|
|
@@ -317,7 +317,7 @@ Generate an alternative version of a completed report for a specific audience.
|
|
|
317
317
|
|
|
318
318
|
#### `updateTemplate(templateId, updates)` → `Template`
|
|
319
319
|
|
|
320
|
-
|
|
320
|
+
Tous les champs sont optionnels (mise à jour partielle). Mêmes champs que `createTemplate`.
|
|
321
321
|
|
|
322
322
|
#### `deleteTemplate(templateId)` → `{ success: true }`
|
|
323
323
|
|
|
@@ -325,15 +325,15 @@ All fields optional (partial update). Same fields as `createTemplate`.
|
|
|
325
325
|
|
|
326
326
|
### `health()`
|
|
327
327
|
|
|
328
|
-
**
|
|
328
|
+
**Réponse :** `{ status: 'ok' | 'degraded'; timestamp: string }`
|
|
329
329
|
|
|
330
330
|
---
|
|
331
331
|
|
|
332
|
-
## 5)
|
|
332
|
+
## 5) Schéma de champs
|
|
333
333
|
|
|
334
|
-
|
|
334
|
+
Si votre organisation a un `field_schema` configuré, ReqVet extrait des champs structurés de chaque consultation en plus de générer le compte rendu HTML.
|
|
335
335
|
|
|
336
|
-
|
|
336
|
+
Exemple de `result.fields` pour un bilan de santé standard :
|
|
337
337
|
|
|
338
338
|
```json
|
|
339
339
|
{
|
|
@@ -347,23 +347,23 @@ Example `result.fields` for a standard checkup:
|
|
|
347
347
|
}
|
|
348
348
|
```
|
|
349
349
|
|
|
350
|
-
`fields`
|
|
350
|
+
`fields` vaut `null` si aucun `field_schema` n'est configuré pour votre organisation. Contactez votre responsable de compte ReqVet pour activer et configurer l'extraction structurée.
|
|
351
351
|
|
|
352
352
|
---
|
|
353
353
|
|
|
354
|
-
## 6)
|
|
354
|
+
## 6) Événements webhook
|
|
355
355
|
|
|
356
|
-
ReqVet
|
|
356
|
+
ReqVet POSTe sur votre `callbackUrl` quand un job change d'état. Tous les événements partagent le même format.
|
|
357
357
|
|
|
358
|
-
###
|
|
358
|
+
### En-têtes
|
|
359
359
|
|
|
360
360
|
```
|
|
361
361
|
Content-Type: application/json
|
|
362
|
-
X-ReqVet-Signature: sha256=<hex> (
|
|
363
|
-
X-ReqVet-Timestamp: <unix_ms> (
|
|
362
|
+
X-ReqVet-Signature: sha256=<hex> (uniquement si l'organisation a un webhook_secret)
|
|
363
|
+
X-ReqVet-Timestamp: <unix_ms> (uniquement si l'organisation a un webhook_secret)
|
|
364
364
|
```
|
|
365
365
|
|
|
366
|
-
###
|
|
366
|
+
### Types d'événements et payloads
|
|
367
367
|
|
|
368
368
|
#### `job.completed`
|
|
369
369
|
|
|
@@ -379,7 +379,7 @@ X-ReqVet-Timestamp: <unix_ms> (only if org has a webhook_secret)
|
|
|
379
379
|
}
|
|
380
380
|
```
|
|
381
381
|
|
|
382
|
-
> `fields`
|
|
382
|
+
> `fields` est absent si l'organisation n'a pas de `field_schema`. `cost` n'est pas dans le webhook — récupérez-le avec `getJob()` si nécessaire.
|
|
383
383
|
|
|
384
384
|
---
|
|
385
385
|
|
|
@@ -399,14 +399,14 @@ X-ReqVet-Timestamp: <unix_ms> (only if org has a webhook_secret)
|
|
|
399
399
|
|
|
400
400
|
#### `job.amended`
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
Envoyé quand un amendement (`amendJob`) se termine avec succès.
|
|
403
403
|
|
|
404
404
|
```json
|
|
405
405
|
{
|
|
406
406
|
"event": "job.amended",
|
|
407
407
|
"job_id": "a1b2c3d4-...",
|
|
408
408
|
"animal_name": "Rex",
|
|
409
|
-
"transcription": "...
|
|
409
|
+
"transcription": "...transcription complète incluant l'amendement...",
|
|
410
410
|
"html": "<section class=\"cr\">...</section>",
|
|
411
411
|
"amendment_number": 1,
|
|
412
412
|
"fields": { "espece": "Chien", "poids": 28.5 },
|
|
@@ -418,7 +418,7 @@ Sent when an amendment (`amendJob`) completes successfully.
|
|
|
418
418
|
|
|
419
419
|
#### `job.amend_failed`
|
|
420
420
|
|
|
421
|
-
|
|
421
|
+
Envoyé quand la transcription d'un amendement échoue. Le compte rendu original est préservé.
|
|
422
422
|
|
|
423
423
|
```json
|
|
424
424
|
{
|
|
@@ -434,7 +434,7 @@ Sent when amendment transcription fails. The original report is preserved.
|
|
|
434
434
|
|
|
435
435
|
#### `job.regenerated`
|
|
436
436
|
|
|
437
|
-
|
|
437
|
+
Envoyé quand `regenerateJob()` se termine.
|
|
438
438
|
|
|
439
439
|
```json
|
|
440
440
|
{
|
|
@@ -449,68 +449,68 @@ Sent when `regenerateJob()` completes.
|
|
|
449
449
|
|
|
450
450
|
---
|
|
451
451
|
|
|
452
|
-
###
|
|
452
|
+
### Politique de retry
|
|
453
453
|
|
|
454
|
-
ReqVet
|
|
454
|
+
ReqVet retente les livraisons webhook échouées **3 fois** avec des délais de 0s, 2s et 5s. Après 3 échecs, l'événement est marqué comme non livré. Implémentez l'idempotence dans votre handler (dédoublonnez sur `job_id + event`).
|
|
455
455
|
|
|
456
456
|
---
|
|
457
457
|
|
|
458
|
-
## 7)
|
|
458
|
+
## 7) Vérification des webhooks
|
|
459
459
|
|
|
460
460
|
```ts
|
|
461
|
-
import { verifyWebhookSignature } from '@reqvet/sdk/webhooks';
|
|
461
|
+
import { verifyWebhookSignature } from '@reqvet-sdk/sdk/webhooks';
|
|
462
462
|
|
|
463
463
|
const { ok, reason } = verifyWebhookSignature({
|
|
464
464
|
secret: process.env.REQVET_WEBHOOK_SECRET!,
|
|
465
|
-
rawBody, //
|
|
466
|
-
signature, // X-ReqVet-Signature
|
|
467
|
-
timestamp, // X-ReqVet-Timestamp
|
|
468
|
-
maxSkewMs: 5 * 60 * 1000, //
|
|
465
|
+
rawBody, // corps brut de la requête — à lire AVANT JSON.parse
|
|
466
|
+
signature, // valeur de l'en-tête X-ReqVet-Signature
|
|
467
|
+
timestamp, // valeur de l'en-tête X-ReqVet-Timestamp
|
|
468
|
+
maxSkewMs: 5 * 60 * 1000, // rejeter les événements de plus de 5 min (défaut)
|
|
469
469
|
});
|
|
470
470
|
```
|
|
471
471
|
|
|
472
|
-
|
|
472
|
+
Raisons de rejet : `missing_headers` `invalid_timestamp` `stale_timestamp` `invalid_signature`
|
|
473
473
|
|
|
474
|
-
|
|
474
|
+
Voir [SECURITY.md](./SECURITY.md) pour un exemple d'implémentation complet avec Next.js.
|
|
475
475
|
|
|
476
476
|
---
|
|
477
477
|
|
|
478
|
-
## 8)
|
|
478
|
+
## 8) Gestion des erreurs
|
|
479
479
|
|
|
480
|
-
|
|
480
|
+
Toutes les méthodes lèvent une `ReqVetError` en cas d'erreur HTTP ou de panne réseau :
|
|
481
481
|
|
|
482
482
|
```ts
|
|
483
|
-
import { ReqVetError } from '@reqvet/sdk';
|
|
483
|
+
import { ReqVetError } from '@reqvet-sdk/sdk';
|
|
484
484
|
|
|
485
485
|
try {
|
|
486
486
|
const report = await reqvet.waitForJob(jobId);
|
|
487
487
|
} catch (err) {
|
|
488
488
|
if (err instanceof ReqVetError) {
|
|
489
|
-
console.error(err.message); //
|
|
490
|
-
console.error(err.status); // HTTP
|
|
491
|
-
console.error(err.body); //
|
|
489
|
+
console.error(err.message); // message lisible par un humain
|
|
490
|
+
console.error(err.status); // statut HTTP (0 pour les erreurs réseau/timeout)
|
|
491
|
+
console.error(err.body); // corps brut de la réponse
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
```
|
|
495
495
|
|
|
496
|
-
|
|
|
497
|
-
|
|
498
|
-
| `400` |
|
|
499
|
-
| `401` |
|
|
500
|
-
| `403` |
|
|
501
|
-
| `404` | Job
|
|
502
|
-
| `429` |
|
|
503
|
-
| `500` |
|
|
496
|
+
| Statut | Signification |
|
|
497
|
+
|--------|---------------|
|
|
498
|
+
| `400` | Erreur de validation — vérifiez `err.body.issues` |
|
|
499
|
+
| `401` | Clé API invalide ou manquante |
|
|
500
|
+
| `403` | Quota mensuel dépassé |
|
|
501
|
+
| `404` | Job ou template introuvable |
|
|
502
|
+
| `429` | Limite de débit dépassée — attendez et réessayez |
|
|
503
|
+
| `500` | Erreur interne ReqVet |
|
|
504
504
|
|
|
505
505
|
---
|
|
506
506
|
|
|
507
|
-
## 9)
|
|
507
|
+
## 9) Checklist d'intégration
|
|
508
508
|
|
|
509
|
-
- [ ] SDK
|
|
510
|
-
- [ ] `listTemplates()`
|
|
511
|
-
- [ ] `metadata`
|
|
512
|
-
- [ ]
|
|
513
|
-
- [ ]
|
|
514
|
-
- [ ]
|
|
515
|
-
- [ ]
|
|
516
|
-
- [ ] `REQVET_API_KEY`
|
|
509
|
+
- [ ] SDK utilisé **côté serveur uniquement** — clé API jamais dans les bundles navigateur
|
|
510
|
+
- [ ] `listTemplates()` appelé au démarrage pour découvrir les `templateId` disponibles
|
|
511
|
+
- [ ] `metadata` utilisé pour corréler les jobs ReqVet avec vos propres enregistrements (`consultationId`, `vetId`, etc.)
|
|
512
|
+
- [ ] L'endpoint webhook gère les 5 types d'événements : `job.completed`, `job.failed`, `job.amended`, `job.amend_failed`, `job.regenerated`
|
|
513
|
+
- [ ] Signature webhook vérifiée sur chaque événement entrant
|
|
514
|
+
- [ ] Vérification anti-replay du timestamp activée (`maxSkewMs`)
|
|
515
|
+
- [ ] Idempotence implémentée — dédoublonnage sur `job_id + event`
|
|
516
|
+
- [ ] `REQVET_API_KEY` et `REQVET_WEBHOOK_SECRET` stockés dans des variables d'environnement, jamais en dur dans le code
|