Eine Datei, keine Abhängigkeiten. Läuft in Node 18+ und modernen Browsern (eingebautes fetch, FormData, Web Crypto). Version 1.7.2 (die Konstante SDK_VERSION in der Datei). Der Client hat eine Methode für jede API-Operation.
Installation
grem.ts herunterladen und ins Projekt legen. Ein npm-Paket gibt es nicht.
Schnellstart
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);
Die Standard-Basisadresse ist https://developers.grem.capital/api/v1 (Option baseUrl). Einen Schlüssel erstellen Sie im Kabinett: API → Schlüssel.
Aufträge
Jede Auftragsantwort enthält jobId (API 1.6.0+). jobs.wait fragt den Status (kostenlos) ab, bis state den Wert completed, partial, failed oder action_required hat. Eine fehlgeschlagene Abfrage (Netzwerk, 5xx, 429) stoppt es nicht: es fragt weiter, bis zu 5 Fehler in Folge:
const job = await grem.text.generate({ city: 'Berlin', totalArea: 64, language: 'de' });
const done = await grem.jobs.wait('text/generate', job.jobId);
if (done.state === 'failed') throw new Error('generation failed');
Eine Berichtsprüfung wartet auf Bestätigung:
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);
Was der Client enthält
| Gruppe | Methoden |
|---|---|
| Schlüssel | ping(), me() |
| Bewertung | valuation.express, valuation.report, valuation.rent, valuation.review, valuation.confirmReview |
| Content | content.generate, text.generate, video.create, video.music, video.endings, avatar.video, avatar.list |
| Materialien | site.create, pdf.create, flyer.create, draft.extract, photo.enhance, floorplan.create |
| Referenzdaten | voices(), toolsStatus(), works(), dictionaries() |
| Aufträge und Dateien | jobs.get, jobs.wait, artifact(path, { range, signal }), uploads.images |
| Objekte | objects.list, get, create, update, delete, setAgency, setAssignee |
| Leads | leads.list, get, create, update, delete, matches, claim, returnToPool |
| Swipe Match | match.list, get, events, sendEvent |
| Webhooks | webhooks.list, create, update, delete, test, deliveries, resend |
| Chat | chat.createSession, listSessions, updateSession, deleteSession, sendMessage, history, stream |
Werkzeuge mit Dateien nehmen FormData - wie es zu füllen ist, steht auf der Seite des jeweiligen Werkzeugs.
Sandbox
Mit einem Testschlüssel bestimmt die Option simulate das Ergebnis jedes simulierten Aufrufs (Sandbox):
const grem = new GremClient({ apiKey: process.env.GREM_TEST_KEY, simulate: 'failed' });
Mit einem Live-Schlüssel wirft die Option simulate schon beim Anlegen des Clients einen Fehler: Der Aufruf würde echt laufen.
Anfragen warten standardmäßig bis zu 5 Minuten (timeoutMs): Der Start eines Werkzeugs kann über eine Minute dauern, und ein früher Abbruch stoppt weder die Arbeit noch ihre Berechnung.
Der Client wiederholt einen abgelehnten Aufruf nach Retry-After, bis zu maxRetries-mal (Standard 3, höchstens 10; 0 schaltet Wiederholungen ab): 429 immer - ein Aufruf über dem Limit wurde nicht verarbeitet; 503 bei Lesezugriffen, bei Schreibzugriffen nur mit Idempotency-Key - ein 503 kann nach einer Nebenwirkung kommen. Ein Retry-After über 30 Sekunden wird nicht abgewartet: Der Fehler wird sofort geworfen. Ihr AbortSignal bricht auch die Pause ab. Übergeben Sie dieses signal an request(). Ohne Retry-After dauern die Pausen 1, 2, 4 ... Sekunden. Ein Upload (uploads.images) wird nach 503 nicht wiederholt (nach 429 schon: der Upload wurde nicht verarbeitet). Ein übergebenes signal ersetzt das Anfrage-Timeout (timeoutMs).
Fehler
Eine Antwort 4xx oder 5xx wirft einen GremError mit status, title, detail, code, errors, requestId und retryAfter (bei 429 und 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);
}
Sichere Wiederholungen
Das letzte Argument von Methoden, die ein Werkzeug starten oder einen Datensatz anlegen, ist der Idempotency-Key:
await grem.pdf.create({ pdfName: 'Präsentation', objectId, language: 'DEU' }, crypto.randomUUID());
uploads.images nimmt ebenfalls einen Schlüssel an, aber die API ignoriert ihn: Ein wiederholter Upload speichert die Dateien erneut.
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, 'Hallo!');
stop.abort(); // when you no longer need the stream
await streaming;
Ohne drittes Argument sendet sendMessage eine zufällige clientMessageId (auch in Node 18). Um eine Nachricht sicher zu wiederholen, übergeben Sie eine eigene ID und verwenden Sie sie erneut: Dieselbe ID wird einmal beantwortet und einmal berechnet.