Docs

SDKs

Offizielle Clients für Node.js und Python für die FeedHorizon-API, mit Typen, Wiederholungen, Paginierung und Webhook-Prüfung.

FeedHorizon hat offizielle SDKs für Node.js und Python. Sie sind schlanke Clients für die REST-API und verwenden für jedes Feld dieselben Namen. Jedes Beispiel auf dieser Seite funktioniert genauso wie die passende cURL-Anfrage in der API-Referenz.

Was die SDKs dir abnehmen:

  • Typen: Anfragen und Antworten sind typisiert, erzeugt aus /openapi.json.
  • Wiederholungen: Netzwerkfehler, Timeouts, 429 und 5xx werden mit Backoff wiederholt, unter Beachtung von Retry-After.
  • Idempotenz: Jeder Schreibzugriff bekommt einen Idempotency-Key, bei jedem Versuch denselben, sodass eine Wiederholung nie einen zweiten Post anlegt.
  • Paginierung: Eine Schleife läuft über alle Seiten einer Liste.
  • Fehler: eine Fehlerklasse pro Status, mit code, param, details und der Request-ID.
  • Webhooks: Signaturprüfung und Parsen in einem Aufruf.
PaketQuellcodeVoraussetzung
Node.js / TypeScript@feedhorizon/sdkbash-bash/feedhorizon-nodeNode.js 20+, auch Deno, Bun und Edge-Runtimes. Keine Abhängigkeiten.
Pythonfeedhorizonbash-bash/feedhorizon-pythonPython 3.10+, braucht httpx

Beide stehen unter der MIT-Lizenz.

Installieren

npm install @feedhorizon/sdk

Client anlegen

Leg unter Dashboard → API & Apps einen API-Key an und setz ihn als Umgebungsvariable FEEDHORIZON_API_KEY. Der Client liest ihn von dort.

import FeedHorizon from '@feedhorizon/sdk';

const client = new FeedHorizon(); // reads FEEDHORIZON_API_KEY

Alternativ übergibst du den Key im Code als apiKey (Node.js) oder api_key (Python). Committe nie einen Key.

Post anlegen

const { data: profiles } = await client.profiles.list();

const post = await client.posts.create({
    profileId: profiles[0].id,
    content: 'Hello from the FeedHorizon SDK!',
    platforms: ['linkedin', 'bluesky'],
    scheduledFor: '2026-11-12T09:00:00+01:00',
});

console.log(post.id, post.status); // post_… scheduled

Methoden geben das Objekt aus data direkt zurück. Lass das Zeitfeld für einen Entwurf weg, oder schick addToQueue oder publishNow statt scheduledFor (siehe Planen). In Python sind Antworten einfache Dicts mit Type Hints, und Parameter behalten die Namen der API (profileId, nicht profile_id).

Listen und Paginierung

Ein List-Aufruf liefert die erste Seite. Lauf mit einer Schleife darüber, um jedes Element aller Seiten zu bekommen; das SDK lädt die nächste Seite, wenn es sie braucht.

const page = await client.posts.list({ status: 'failed', limit: 50 });
console.log(page.data.length, page.hasNextPage());

for await (const post of client.posts.list({ updatedSince: '2026-11-01T00:00:00Z' })) {
    console.log(post.id, post.status);
}

from ist in Python ein Schlüsselwort, deshalb heißt der Kalenderfilter von posts.list dort from_.

Fehler

Jeder API-Fehler ist ein APIError mit status, code, message, param, details und der Request-ID. Verzweige anhand von code; Fehler listet alle auf.

import { ConflictError, InvalidRequestError } from '@feedhorizon/sdk';

try {
    await client.posts.update(postId, { content: 'New text' });
} catch (error) {
    if (error instanceof InvalidRequestError) {
        for (const d of error.details) console.log(d.code, d.param, d.message);
    } else if (error instanceof ConflictError && error.code === 'post_not_editable') {
        // already publishing or published
    } else {
        throw error;
    }
}
KlasseStatus
InvalidRequestError400, 422
AuthenticationError401
PermissionDeniedError403
NotFoundError404
ConflictError409
RateLimitError429, mit der Wartezeit in Sekunden als retryAfter / retry_after
InternalServerError5xx
APIConnectionError, APITimeoutErrorKeine Antwort vom Server

Gib die Request-ID (requestId / request_id) an, wenn du den Support kontaktierst.

Wiederholungen und Idempotenz

Fehlgeschlagene Anfragen werden standardmäßig zweimal wiederholt. Übergib einen eigenen Idempotency-Key, damit ein Schreibzugriff auch über Neustarts des Prozesses hinweg sicher wiederholbar ist, zum Beispiel aus einer Job-Queue:

await client.posts.create(params, { idempotencyKey: `launch-${campaignId}` });

// per client or per request
const patient = new FeedHorizon({ maxRetries: 5, timeout: 30_000 });
await client.posts.get(postId, { maxRetries: 0, timeout: 5_000 });

Wie der Server wiederholte Keys behandelt, steht unter Idempotenz.

Medien

// From a public URL
const image = await client.media.import('https://example.com/launch.jpg');

// From a file (up to 5 GB)
import { readFile } from 'node:fs/promises';
const video = await client.media.upload({ file: await readFile('teaser.mp4'), filename: 'teaser.mp4', mimeType: 'video/mp4' });

await client.posts.create({ profileId, content: 'The teaser is out', platforms: ['instagram'], mediaIds: [image.id, video.id], addToQueue: true });

upload meldet die Datei an und lädt die Bytes in einem Aufruf hoch. Siehe Medien hochladen.

Webhooks

Prüf die Signatur gegen den unveränderten Request-Body und verarbeite dann das Event. In TypeScript ist event.data passend zu event.event typisiert.

import express from 'express';
import { constructWebhookEvent, WebhookVerificationError } from '@feedhorizon/sdk';

app.post('/webhooks/feedhorizon', express.raw({ type: 'application/json' }), async (req, res) => {
    let event;
    try {
        event = await constructWebhookEvent({
            payload: req.body,
            signature: req.get('X-Webhook-Signature'),
            secret: process.env.FEEDHORIZON_WEBHOOK_SECRET!,
        });
    } catch (error) {
        if (error instanceof WebhookVerificationError) return res.sendStatus(400);
        throw error;
    }
    res.sendStatus(200);

    if (event.event === 'post.target.failed') {
        console.log(event.data.platform, event.data.error?.code);
    }
});

Events, die älter als fünf Minuten sind, werden abgelehnt; das verhindert Replays. Alle Events stehen unter Webhooks.

Async Python

AsyncFeedHorizon hat dieselben Methoden wie FeedHorizon, mit await:

import asyncio
from feedhorizon import AsyncFeedHorizon


async def main() -> None:
    async with AsyncFeedHorizon() as client:
        post = await client.posts.get("post_…")
        async for failed in client.posts.list(status="failed"):
            print(failed["id"])


asyncio.run(main())

Ressourcen

Node.jsPythonMethoden
client.me()client.me()Organisation, Tarif, Rate Limit und Scopes des Keys
client.postsclient.postslist, get, create, validate, update, delete, publish, cancel, retry, duplicate
client.mediaclient.medialist, get, create, import (Python: import_url), upload, delete
client.profilesclient.profileslist, get, create, update, delete
client.profiles.queueclient.profiles.queueget, set, slots
client.accountsclient.accountslist, get, delete, boards, tiktokCreator (Python: tiktok_creator)
client.platformsclient.platformslist, get
client.platformInvitesclient.platform_inviteslist, create, delete (Connect-Links)
client.webhooksclient.webhookslist, get, create, update, delete, test
client.apiKeysclient.api_keyslist, create, delete

Konfiguration

Node.jsPythonStandard
apiKeyapi_keyFEEDHORIZON_API_KEY
baseURLbase_urlFEEDHORIZON_BASE_URL, sonst https://feedhorizon.com/api/v1
timeouttimeout60 Sekunden (60000 ms in Node.js)
maxRetriesmax_retries2
defaultHeadersdefault_headerskeine
fetchhttp_clientglobales fetch / ein neuer httpx-Client

Andere Sprachen

Jeder Endpunkt, jedes Feld und jeder Webhook-Payload steht in /openapi.json (OpenAPI 3.1). Nutz die Datei mit einem beliebigen OpenAPI-Client-Generator, oder ruf die API mit einfachem HTTP auf, wie die cURL-Beispiele zeigen.

Versionen

Die SDKs folgen Semantic Versioning. Neue API-Felder und Endpunkte kommen in Minor-Releases; was die API selbst zusagt, steht unter Versionierung. Release Notes findest du im CHANGELOG und in den GitHub-Releases jedes Repositorys.