DocsAllemagneAfficher la version internationale de la base de connaissances

SDK TypeScript

Dernière mise à jour: 2026-11-067 min de lecture

Un seul fichier, sans dépendances. Fonctionne avec Node 18+ et les navigateurs modernes (fetch, FormData et Web Crypto intégrés). Version 1.11.0 (la constante SDK_VERSION dans le fichier). Le client dispose d'une méthode pour chaque opération de l'API.

Installation

Téléchargez grem.ts et placez-le dans votre projet. Il n'existe pas de paquet npm.

Démarrage rapide

import { GremClient } from './grem';

const grem = new GremClient({ apiKey: process.env.GREM_API_KEY });

const { estimate } = await grem.valuation.express({
  propertyCategory: 'apartment',
  addressText: 'Torstraße 12, Berlin',
  totalArea: 64,
});
console.log(estimate.pricePoint, estimate.currency);

L'adresse de base par défaut est https://developers.grem.capital/api/v1 (option baseUrl). Créez une clé dans l'espace personnel : API → Clés.

Tâches

Chaque réponse de tâche contient jobId (API 1.6.0+). jobs.wait interroge le statut (gratuit) jusqu'à ce que state vaille completed, partial, failed ou action_required. Une interrogation échouée (réseau, 5xx, 429) ne l'arrête pas : il continue d'interroger, jusqu'à 5 échecs consécutifs :

const job = await grem.text.generate({ city: 'Berlin', totalArea: 64, language: 'en' });
const done = await grem.jobs.wait('text/generate', job.jobId);
if (done.state === 'failed') throw new Error('generation failed');

Une vérification de rapport attend une confirmation :

const form = new FormData();
form.append('file', pdfBlob, 'report.pdf');
const review = await grem.valuation.review(form);
await grem.valuation.confirmReview(review.jobId);
const result = await grem.jobs.wait('valuation/review', review.jobId);

Contenu du client

GroupeMéthodes
cléping(), me()
estimationvaluation.express, valuation.report, valuation.rent, valuation.review, valuation.confirmReview
contenucontent.generate, text.generate, video.create, video.music, video.endings, avatar.video, avatar.list
supportssite.create, pdf.create, flyer.create, draft.extract, photo.enhance, floorplan.create
référencevoices(), toolsStatus(), works(), dictionaries()
tâches et fichiersjobs.get, jobs.wait, jobs.result, artifact(path, { range, signal }), uploads.images
biensobjects.list, get, create, update, delete, setAgency, setAssignee
leadsleads.list, get, create, update, delete, matches, claim, returnToPool
Swipe Matchmatch.list, get, events, sendEvent
webhookswebhooks.list, create, update, delete, test, deliveries, resend
chatchat.createSession, listSessions, updateSession, deleteSession, sendMessage, history, stream

Les outils qui prennent des fichiers reçoivent un FormData - la façon de le remplir est décrite sur la page de chaque outil.

Bac à sable

Avec une clé de test, l'option simulate choisit le résultat de chaque appel simulé (Bac à sable) :

const grem = new GremClient({ apiKey: process.env.GREM_TEST_KEY, simulate: 'failed' });

Avec une clé réelle, l'option simulate lève une erreur dès la création du client : l'appel serait exécuté pour de vrai.

Par défaut, les requêtes attendent jusqu'à 5 minutes (timeoutMs) : le lancement d'un outil peut prendre plus d'une minute, et abandonner trop tôt n'arrête ni le travail ni sa facturation.

Le client répète un appel refusé après Retry-After, jusqu'à maxRetries fois (3 par défaut, 10 au maximum ; 0 désactive les nouvelles tentatives) : toujours pour 429 - un appel limité en débit n'a pas été traité ; pour 503 en lecture, et en écriture seulement si vous passez un Idempotency-Key - un 503 peut survenir après un effet de bord. Un Retry-After supérieur à 30 secondes n'est pas attendu : l'erreur est levée immédiatement. Votre AbortSignal annule aussi la pause. Passez ce signal à request(). Sans Retry-After, les pauses sont de 1, 2, 4 ... secondes. Un envoi de fichiers (uploads.images) n'est pas répété après 503 (il l'est après 429 : l'envoi n'a pas été traité). Un signal que vous passez remplace le délai d'attente de la requête (timeoutMs). Depuis la version 1.8.0, le client répète aussi un appel avec le même Idempotency-Key après une coupure réseau ou l'expiration du délai de la requête, après 502, 504, 524 (le travail a peut-être abouti - la répétition le renvoie sans seconde facturation) et après 409 idempotency_conflict (le premier appel est encore en cours) : pauses d'environ 1, 2, 4 ... secondes, 30 au maximum, pour une durée totale ne dépassant pas retryWindowMs (10 minutes par défaut). Les écritures sans clé (envois de fichiers, gestion des webhooks) ne sont pas répétées après une coupure. maxRetries: 0 désactive toutes les répétitions.

Appels longs

valuation.express et valuation.rent peuvent prendre de 30 à 150 secondes, et une réponse qui n'a pas commencé dans les ~100 secondes est coupée avec 524. Avec l'option respondAsync, le client envoie Prefer: respond-async, reçoit immédiatement une tâche et l'interroge (gratuit) ; la méthode se résout avec le même résultat que l'appel synchrone, et une tâche échouée lève une GremError :

const grem = new GremClient({ apiKey, respondAsync: true });         // all long calls
const est = await grem.valuation.express(input);                     // same result
await grem.valuation.rent(input, undefined, { respondAsync: true }); // or per call

Pour interroger vous-même : grem.jobs.result('valuation/express', jobId) (ou jobs.get / jobs.wait), ou abonnez-vous à express.completed / express.failed et rent.completed / rent.failed.

Depuis la version 1.9.0, floorplan.create et valuation.review acceptent la même option : leur envoi est traité (une minute ou plus pour un gros document) avant que la tâche n'existe. Avec respondAsync, les fichiers sont envoyés une seule fois, le serveur répond immédiatement avec une tâche de requête, et la méthode se résout avec le même Job que sans l'option (une vérification revient en action_required - appelez alors confirmReview). Une tâche de requête interrompue par un redémarrage du service (code: interrupted, rien n'est facturé) est renvoyée avec le même formulaire et le même Idempotency-Key, deux fois au maximum.

const plan = await grem.floorplan.create(form, undefined, { respondAsync: true });

Depuis 1.10.0, draft.extract accepte aussi l’option respondAsync : la méthode renvoie le même brouillon que l’appel synchrone. Depuis 1.11.0, site.create accepte aussi cette option.

Erreurs

Une réponse 4xx ou 5xx lève une GremError avec status, title, detail, code, errors, requestId et retryAfter (pour 429 et 503) :

import { GremError } from './grem';

try {
  await grem.text.generate({});
} catch (e) {
  if (e instanceof GremError) console.error(e.status, e.title, e.code, e.detail);
}

Nouvelles tentatives sans risque

Le dernier argument des méthodes qui lancent un outil ou créent un enregistrement est le Idempotency-Key :

await grem.pdf.create({ pdfName: 'Presentation', objectId, language: 'ENG' }, crypto.randomUUID());

uploads.images accepte aussi une clé, mais l'API l'ignore : un envoi répété enregistre à nouveau les fichiers.

Depuis la version 1.8.0, chaque POST que l'API rend idempotent (outils, estimation express, biens, leads, événements Swipe Match) reçoit une clé - la vôtre ou une clé créée par le client - et toutes les répétitions de l'appel la réutilisent : un outil payant n'est facturé qu'une fois, même si la connexion est coupée. Passez votre propre clé pour pouvoir répéter l'appel plus tard vous-même (par exemple après un redémarrage de votre processus) ; GremError.idempotencyKey contient la clé utilisée par l'appel.

Webhooks

import { verifyWebhookSignature } from './grem';

app.post('/grem-hook', express.raw({ type: 'application/json' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  const ok = await verifyWebhookSignature(process.env.GREM_WEBHOOK_SECRET, req.get('x-grem-signature'), raw);
  if (!ok) return res.status(400).send('invalid signature');
  const event = JSON.parse(raw);
  res.sendStatus(200);
});

Chat

const session = await grem.chat.createSession();
const stop = new AbortController();
const streaming = grem.chat
  .stream(session.sessionId, (data) => console.log(data), stop.signal)
  .catch((e) => { if (e.name !== 'AbortError') throw e; }); // stop.abort() rejects with AbortError
await grem.chat.sendMessage(session.sessionId, 'Hello!');
stop.abort(); // when you no longer need the stream
await streaming;

Sans troisième argument, sendMessage envoie un clientMessageId aléatoire (Node 18 compris). Pour relancer un message sans risque, passez votre propre identifiant et réutilisez-le : un même identifiant ne reçoit qu'une réponse et n'est facturé qu'une fois.

Voir aussi

Cet article vous a-t-il aidé ?