npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reqvet-sdk/sdk

v2.3.0

Published

Official JavaScript SDK for the ReqVet veterinary report generation API.

Downloads

57

Readme

@reqvet-sdk/sdk

SDK JavaScript/TypeScript officiel pour l'API ReqVet — génération de comptes rendus vétérinaires par IA à partir d'enregistrements audio.

npm version License: MIT Node.js ≥ 18

Fonctionnalités

  • Uploader un enregistrement audio (uploadAudio)
  • Générer un compte rendu vétérinaire (createJob, generateReport)
  • Suivre les jobs — via webhook ou polling (getJob, waitForJob, listJobs)
  • Amender un compte rendu terminé avec un audio complémentaire (amendJob)
  • Régénérer avec de nouvelles instructions (regenerateJob)
  • Reformuler pour une audience spécifique — propriétaire, référé, spécialiste (reformulateReport)
  • Gérer les templates (listTemplates, createTemplate, updateTemplate, deleteTemplate)
  • Vérifier les webhooks avec HMAC (@reqvet-sdk/sdk/webhooks)
  • Provisionner et gérer des cliniques en mode revendeur multi-tenant (createOrganization, listOrganizations, updateOrganization, deactivateOrganization)

Note : ce SDK n'inclut pas d'enregistreur audio. Votre application gère l'enregistrement et passe un File, Blob ou Buffer au SDK.

Installation

npm install @reqvet-sdk/sdk

Nécessite Node.js ≥ 18. Fonctionne dans les navigateurs modernes pour les méthodes client (Blob/FormData requis pour l'upload).

Avant votre premier appel

Votre responsable de compte ReqVet vous fournira trois variables d'environnement :

REQVET_API_KEY=rqv_live_...
REQVET_BASE_URL=https://api.reqvet.com
REQVET_WEBHOOK_SECRET=...   # uniquement si vous utilisez les webhooks

Chaque job nécessite un templateId. Appelez listTemplates() en premier pour découvrir ce qui est disponible :

const { system, custom } = await reqvet.listTemplates();
// system = templates fournis par ReqVet, visibles par toutes les organisations (lecture seule)
// custom = templates créés par votre organisation

const templateId = system[0].id;

Démarrage rapide

Flux webhook (recommandé)

Pour les intégrations serveur (Next.js, Express…), utilisez getSignedUploadUrl() qui uploade le fichier directement dans Supabase sans passer par une Vercel Serverless Function — pas de limite de taille.

import ReqVet from '@reqvet-sdk/sdk';

const reqvet = new ReqVet(process.env.REQVET_API_KEY!, {
  baseUrl: process.env.REQVET_BASE_URL,
});

// 1. Obtenir une URL signée Supabase (requête JSON légère, pas de fichier)
const { uploadUrl, path } = await reqvet.getSignedUploadUrl(
  'consultation.webm',
  'audio/webm',
);

// 2. Uploader directement vers Supabase (contourne Vercel, pas de limite de taille)
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'audio/webm' },
  body: audioBuffer, // Buffer | Blob | File
});

// 3. Créer un job — ReqVet POSTera le résultat sur votre webhook quand il sera prêt
const job = await reqvet.createJob({
  audioFile: path,
  animalName: 'Rex',
  templateId: 'your-template-uuid',
  callbackUrl: 'https://your-app.com/api/reqvet/webhook',
  metadata: { consultationId: 'abc123' },
});
// { job_id: '...', status: 'pending' }

uploadAudio() vs getSignedUploadUrl()

uploadAudio() est pratique pour des fichiers légers (< 4 MB) ou des contextes navigateur. Pour les proxies serveur, préférez getSignedUploadUrl() : le fichier va directement dans Supabase, sans passer par /api/v1/upload (Vercel Serverless Function, limite ~4.5 MB).

Votre webhook reçoit un événement job.completed :

{
  "event": "job.completed",
  "job_id": "a1b2c3d4-...",
  "animal_name": "Rex",
  "html": "<section class=\"cr\">...</section>",
  "transcription": "Le vétérinaire examine Rex...",
  "fields": { "espece": "Chien", "poids": 28.5 },
  "metadata": { "consultationId": "abc123" }
}

Flux polling (plus simple pour le développement)

const report = await reqvet.generateReport({
  audio: audioFile,
  animalName: 'Rex',
  templateId: 'your-template-uuid',
  waitForResult: true,
  onStatus: (s) => console.log(s),
});
// { jobId, html, fields, transcription, cost, metadata }

Vérifier un webhook entrant

import { verifyWebhookSignature } from '@reqvet-sdk/sdk/webhooks';

export async function POST(req: NextRequest) {
  const rawBody = await req.text();

  const { ok, reason } = verifyWebhookSignature({
    secret: process.env.REQVET_WEBHOOK_SECRET!,
    rawBody,
    signature: req.headers.get('x-reqvet-signature') ?? '',
    timestamp: req.headers.get('x-reqvet-timestamp') ?? '',
  });

  if (!ok) return new Response('Unauthorized', { status: 401 });

  const event = JSON.parse(rawBody);
  // event.event, event.job_id, event.html, event.metadata ...
}

API

Génération de comptes rendus

| Méthode | Description | |---------|-------------| | getSignedUploadUrl(fileName, contentType) | URL signée Supabase pour upload direct (recommandé serveur) | | uploadAudio(audio, fileName?) | Uploader un fichier audio via ReqVet (limite Vercel ~4.5 MB) | | generateReport(params) | Upload + création de job (helper tout-en-un) | | createJob(params) | Créer un job de génération | | listJobs(options?) | Lister les jobs avec pagination et filtre par statut | | getJob(jobId) | Obtenir le statut et le résultat d'un job | | waitForJob(jobId, onStatus?) | Attendre en polling la fin d'un job | | regenerateJob(jobId, options?) | Régénérer un compte rendu terminé | | amendJob(jobId, params) | Ajouter un audio complémentaire à un job terminé | | reformulateReport(jobId, params) | Générer une version adaptée à une audience | | listReformulations(jobId) | Lister toutes les reformulations d'un job | | listTemplates() | Lister les templates disponibles ({ system, custom }) | | getTemplate(templateId) | Obtenir un template par son ID | | createTemplate(params) | Créer un template personnalisé | | updateTemplate(templateId, updates) | Mettre à jour un template | | deleteTemplate(templateId) | Supprimer un template | | health() | Vérification de l'état de l'API |

API Partenaire / Revendeur

Ces méthodes nécessitent une clé API revendeur (rqv_live_... avec role='reseller'), distincte de la clé d'une clinique standard. Contactez votre responsable de compte ReqVet pour obtenir une clé revendeur.

| Méthode | Description | |---------|-------------| | listOrganizations() | Lister toutes les cliniques provisionnées par le revendeur | | createOrganization(params) | Provisionner une nouvelle clinique (génère sa clé API et son webhook secret) | | getOrganization(orgId) | Obtenir le détail et l'usage du mois d'une clinique | | updateOrganization(orgId, updates) | Modifier le quota, le statut ou le webhook d'une clinique | | deactivateOrganization(orgId) | Suspendre une clinique et révoquer ses clés API (soft delete) |

Événements webhook

ReqVet déclenche 5 types d'événements : job.completed, job.failed, job.amended, job.amend_failed, job.regenerated.

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.

Voir SDK_REFERENCE.md §6 pour la structure complète des payloads de chaque événement.

Intégration revendeur (multi-tenant)

Si vous êtes un éditeur logiciel intégrant ReqVet pour vos clients (cliniques), vous disposez de deux types de clés :

| Clé | Variable | Usage | |-----|----------|-------| | Clé revendeur | REQVET_RESELLER_KEY | Provisionner et administrer les cliniques — jamais pour générer des jobs | | Clé clinique | stockée dans votre DB | Faire les appels de génération pour cette clinique spécifique |

1 — Onboarding : provisionner une clinique

Appelez createOrganization à chaque fois qu'une nouvelle clinique souscrit à votre service. Utilisez votre identifiant interne comme externalId — c'est le pont entre vos deux systèmes.

import ReqVet from '@reqvet-sdk/sdk';

const reseller = new ReqVet(process.env.REQVET_RESELLER_KEY!);

const result = await reseller.createOrganization({
  name: 'Clinique du Parc',
  contactEmail: '[email protected]',
  externalId: String(clinic.id),  // votre ID interne → idempotence garantie
  monthlyQuota: 500,
  webhookUrl: 'https://votre-app.com/webhooks/reqvet',
});

if (result.api_key) {
  // Première création — stocker immédiatement, chiffré au repos
  // api_key et webhook_secret ne sont retournés qu'une seule fois
  await db.clinics.update(clinic.id, {
    reqvet_org_id:    result.organization.id,
    reqvet_api_key:   encrypt(result.api_key),      // rqv_live_...
    reqvet_wh_secret: encrypt(result.webhook_secret), // whsec_...
  });
}
// Si !result.api_key → clinique déjà provisionnée (idempotent), clé déjà en base

2 — Runtime : appeler ReqVet pour le bon utilisateur

À chaque consultation, récupérez la clé de la clinique de l'utilisateur connecté et faites l'appel côté serveur. La clé ne sort jamais du backend.

// Handler server-side — appelé quand un vétérinaire lance une transcription
async function transcribe(userId: string, audioBuffer: Buffer) {
  // Identifier la clinique de l'utilisateur dans VOTRE système
  const clinic = await db.getClinicByUser(userId);

  // Déchiffrer la clé de cette clinique — côté serveur uniquement
  const reqvet = new ReqVet(decrypt(clinic.reqvet_api_key));

  // Upload direct Supabase (pas de limite de taille)
  const { uploadUrl, path } = await reqvet.getSignedUploadUrl('consultation.webm', 'audio/webm');
  await fetch(uploadUrl, { method: 'PUT', body: audioBuffer });

  // Injecter clinicId dans metadata → permet de router les webhooks entrants
  return reqvet.createJob({
    audioFile: path,
    animalName: consultation.animalName,
    templateId: clinic.reqvet_template_id,
    callbackUrl: 'https://votre-app.com/webhooks/reqvet',
    metadata: { clinicId: clinic.id, userId },
  });
}

3 — Webhooks entrants : router vers la bonne clinique

Vos webhooks arrivent sur un seul endpoint. Utilisez metadata.clinicId (injecté au createJob) pour identifier la clinique et vérifier la signature avec son propre secret.

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const event = JSON.parse(rawBody);

  const clinic = await db.getClinic(event.metadata?.clinicId);

  const { ok } = verifyWebhookSignature({
    secret: decrypt(clinic.reqvet_wh_secret), // secret de CETTE clinique
    rawBody,
    signature: req.headers.get('x-reqvet-signature') ?? '',
    timestamp: req.headers.get('x-reqvet-timestamp') ?? '',
  });

  if (!ok) return new Response('Unauthorized', { status: 401 });

  if (event.event === 'job.completed') {
    await db.saveReport(clinic.id, event.job_id, event.html, event.fields);
  }
}

4 — Administration : quotas, suspension, monitoring

// Lister toutes les cliniques avec leur usage du mois
const { organizations } = await reseller.listOrganizations();
// [{ id, name, is_active, monthly_quota, usage: { jobs_this_month, quota_remaining } }]

// Modifier le quota (ex. changement de plan)
await reseller.updateOrganization(orgId, { monthlyQuota: 1000 });

// Suspendre une clinique — révoque ses clés API en cascade
await reseller.updateOrganization(orgId, { isActive: false });

// Réactiver
await reseller.updateOrganization(orgId, { isActive: true });

// Désactiver définitivement (soft delete — données conservées pour le RGPD)
await reseller.deactivateOrganization(orgId);

Voir SDK_REFERENCE.md §9 pour le schéma DB complet, les règles impératives et les cas limites (rotation de clé, etc.).

TypeScript

Définitions TypeScript complètes incluses :

import type {
  ReqVetReport,
  JobSummary,
  ListJobsResult,
  Template,
  ReqVetReformulation,
  ExtractedFields,
  // Partner / Reseller
  PartnerOrganization,
  OrganizationUsage,
  CreateOrganizationParams,
  UpdateOrganizationParams,
  CreateOrganizationResult,
} from '@reqvet-sdk/sdk';

Pour aller plus loin

  • SDK_REFERENCE.md — documentation complète des paramètres et réponses, tous les payloads webhook, schéma des champs, codes d'erreur
  • SECURITY.md — bonnes pratiques de sécurité, pattern proxy, exemple complet de vérification webhook

Sécurité

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.

Licence

MIT