Rekomi Docs
Für Entwickler
Developers

API für das Sub-Affiliate-Recruiting

Endpunkte, Aufbau der Override-Zeilen, Webhook-Payloads und Verhalten des Bewerbungsformulars für das begrenzte 2-stufige Sub-Affiliate-Modell.

Diese Seite ist die Entwicklerseite zum Sub-Affiliate-Recruiting: Die Konzeptseite für Marken erklärt das „Was“ und das „Warum“, diese Seite zeigt die Datenformate, die tatsächlich über die API laufen.

Es gibt fünf Endpunkte, einen neuen Aufbau für Conversion-Zeilen, eine Variante eines Webhooks und zwei Felder im Bewerbungsformular. Alles ist auf eine einzige Rekrutierungsebene begrenzt, mit fester Obergrenze; es gibt keine Weitergabe über eine Kette.

Endpunkte

Alle fünf liegen unter /api/v1/*. Die drei Endpunkte für Marken akzeptieren die übliche Authentifizierung per API-Schlüssel mit Authorization: Bearer rk_live_* und zusätzlich denselben JWT-Weg wie das Dashboard im Produkt. Die beiden Endpunkte unter /me/sub-affiliate/* gehören zur Seite der Affiliates und akzeptieren nur das JWT des Affiliates, nie einen API-Schlüssel.

GET /api/v1/programs/{id}/sub-affiliate-config

Scope (Berechtigungsumfang): read. Liefert die aktuelle Sub-Affiliate-Einstellung einer Kampagne.

curl -sS https://api.rekomi.com/api/v1/programs/0789abcd-.../sub-affiliate-config \
  -H "Authorization: Bearer $REKOMI_API_KEY"

Antwort:

{
  "enabled": true,
  "percent": 10.0
}
  • enabled: ob das Werben in dieser Kampagne eingeschaltet ist.
  • percent: der Override-Prozentsatz auf die Provision des Geworbenen. Wertebereich 0 bis 100. Ist enabled false, wird das Feld trotzdem zurückgegeben (es greift dann nur bei neuen Conversions nicht).

PUT /api/v1/programs/{id}/sub-affiliate-config

Scope: read_write. Rolle: Owner (beim JWT). Plan: in jedem Plan enthalten. Eine bestätigte E-Mail-Adresse ist erforderlich.

Wird im Audit-Log als program.sub_affiliate_config_changed festgehalten.

curl -sS -X PUT https://api.rekomi.com/api/v1/programs/0789abcd-.../sub-affiliate-config \
  -H "Authorization: Bearer $REKOMI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "percent": 10
  }'

Antwort (200):

{
  "enabled": true,
  "percent": 10.0
}

Fehler:

HTTPerrorUrsache
400body_requiredDer JSON-Anfrageinhalt fehlt oder ist leer
400unsupported_valueProzentwert außerhalb von [0, 100] oder keine Zahl
403email_verification_requiredDer Aufrufer im Dashboard hat seine E-Mail-Adresse nicht bestätigt
403(leer)Der Aufrufer ist nicht Owner
404(leer)Die Kampagne gehört nicht zu deiner Organisation

GET /api/v1/me/sub-affiliate/link?programId={id}

Scope: read. Seite der Affiliates. Liefert den persönlichen Rekrutierungslink des aufrufenden Affiliates für eine Kampagne. Authentifiziert wird mit dem /a-JWT des Affiliates, nicht mit einem API-Schlüssel der Marke.

curl -sS "https://api.rekomi.com/api/v1/me/sub-affiliate/link?programId=0789abcd-..." \
  -H "Authorization: Bearer $AFFILIATE_JWT"

Antwort:

{
  "affiliateId": "01234567-...",
  "programId": "0789abcd-...",
  "programSlug": "default",
  "url": "https://your-brand.example.com/default?recruited_by=v6media"
}

Für das Token recruited_by gilt: Slug zuerst. Es ist der kontoweite ?via=-Slug des Affiliates, falls er einen hat (oben v6media), sonst sein Link-Slug in der Kampagne, und nur wenn es keinen der beiden Slugs gibt, die GUID der Affiliate-ID.

Fehler:

HTTPerrorUrsache
403email_verification_requiredDer aufrufende Affiliate hat seine E-Mail-Adresse nicht bestätigt (wird vor allem anderen geprüft)
400program_id_requiredDer Query-Parameter programId fehlt
400sub_affiliate_recruiting_disabledDie Kampagne hat enabled = false
403(leer)Der aufrufende Affiliate ist in der Kampagne nicht Approved
404(leer)Der aufrufende Affiliate kann die Kampagne nicht sehen (er ist kein Mitglied)
409portal_not_configuredDie Marke hat keinen Host für ein öffentliches Portal, auf dem die URL aufgebaut werden kann

GET /api/v1/me/sub-affiliate/recruits

Scope: read. Seite der Affiliates. Listet die Geworbenen des aufrufenden Affiliates auf. Mit Cursor-Paginierung.

curl -sS "https://api.rekomi.com/api/v1/me/sub-affiliate/recruits?take=50" \
  -H "Authorization: Bearer $AFFILIATE_JWT"

Antwort:

{
  "items": [
    {
      "affiliateId": "fed00b00-...",
      "email": "recruit@example.com",
      "fullName": "Recruited Person",
      "status": "Approved",
      "totalCommissionGeneratedCents": 12400,
      "overrideEarnedCents": 1240,
      "currency": "USD",
      "joinedAt": "2026-05-12T10:00:00Z"
    }
  ],
  "nextCursor": null
}
  • totalCommissionGeneratedCents: die eigenen Provisionseinnahmen dieses Geworbenen (ohne Override-Zeilen, damit nichts doppelt gezählt wird, wenn der Geworbene später selbst jemanden wirbt).
  • overrideEarnedCents: die gesamte Override-Provision, die der aufrufende Affiliate mit diesem Geworbenen verdient hat, in currency.
  • Ausstehende Bewerber und abgelehnte Bewerbungen erscheinen nicht in der Liste; ein Geworbener taucht auf, sobald die Marke ihn freigibt (Geworbene, die später pausiert oder gesperrt werden, bleiben mit ihrem Verlauf in der Liste). Nur freigegebene (Approved) Geworbene bringen Override-Provision ein.

GET /api/v1/affiliates/{id}/sub-affiliates

Scope: read. Detailansicht für die Marke: Damit sieht sich die handelnde Person bei der Marke die Geworbenen eines beliebigen Affiliates an. Liefert ein flaches Array (ohne Paginierungs-Wrapper) mit leicht anderen Feldnamen als der Endpunkt auf der Seite der Affiliates.

curl -sS "https://api.rekomi.com/api/v1/affiliates/01234567-.../sub-affiliates" \
  -H "Authorization: Bearer $REKOMI_API_KEY"
[
  {
    "id": "fed00b00-...",
    "email": "recruit@example.com",
    "fullName": "Recruited Person",
    "status": "Approved",
    "totalCommissionCents": 12400,
    "overrideEarnedCents": 1240,
    "currency": "USD"
  }
]

Override-Zeile einer Conversion

Wirbt Affiliate A den Affiliate B und schließt B einen Verkauf ab, werden zwei Conversion-Zeilen geschrieben: zuerst die Provisionszeile des Geworbenen, danach die Override-Zeile in einem eigenen, idempotenten Schreibvorgang. Schlägt das Schreiben der Override-Zeile einmal fehl, wird sie automatisch nachgetragen, sobald dasselbe Verkaufsereignis erneut zugestellt wird. So geht keine Override-Provision verloren.

  1. Provisionszeile für B. Sieht aus wie eine normale Conversion. AmountCents ist der Verkauf, CommissionCents die Provision von B, AttributionMethod der Weg, über den der Verkauf zugeordnet wurde (zum Beispiel coupon oder metadata_or_customer). ParentAffiliateConversionId ist null.
  2. Override-Zeile für A. AmountCents = 0, CommissionCents = (B.commission × Program.SubAffiliateCommissionPercent / 100), auf die kleinste Währungseinheit gerundet, und zwar mit Banker's Rounding (bei genau einer Hälfte wird zur geraden Zahl gerundet, MidpointRounding.ToEven). AttributionMethod = "sub_affiliate_override". ParentAffiliateConversionId zeigt auf die ID der Provisionszeile.

Beispielabfrage der Conversion-Liste mit beiden Zeilen:

curl -sS "https://api.rekomi.com/api/v1/conversions?programId=0789abcd-...&take=50" \
  -H "Authorization: Bearer $REKOMI_API_KEY"

Antwort (nur die relevanten Felder):

{
  "items": [
    {
      "id": "c0nv0parent-...",
      "affiliateId": "01234567-B-...",
      "programId": "0789abcd-...",
      "amountCents": 10000,
      "currency": "USD",
      "commissionCents": 2000,
      "attributionMethod": "coupon",
      "parentAffiliateConversionId": null,
      "status": "Approved"
    },
    {
      "id": "c0nv0override-...",
      "affiliateId": "01234567-A-...",
      "programId": "0789abcd-...",
      "amountCents": 0,
      "currency": "USD",
      "commissionCents": 200,
      "attributionMethod": "sub_affiliate_override",
      "parentAffiliateConversionId": "c0nv0parent-...",
      "status": "Approved"
    }
  ],
  "nextCursor": null,
  "hasMore": false
}

Hinweise:

  • Override-Zeilen haben immer amountCents = 0. Der Verkaufsbetrag steht in der Provisionszeile; ihn in der Override-Zeile zu wiederholen, würde den Umsatz in Dashboards doppelt zählen.
  • Override-Zeilen haben immer commissionCents > 0. Rundet die berechnete Override-Provision auf null (sehr kleine Provision mal sehr kleiner Prozentsatz), wird keine Zeile angelegt.
  • parentAffiliateConversionId ist ein Fremdschlüssel auf dieselbe Tabelle Conversion. Damit verknüpfst du Override-Zeilen mit dem Verkauf, aus dem sie entstanden sind.

Erstattungen wirken auf die Override-Zeile

Wird die zugrunde liegende Conversion erstattet (teilweise oder ganz), egal über welchen Erstattungsweg (Webhooks des Zahlungsanbieters, der Endpunkt für Erstattungs-Tracking oder der S2S-Endpunkt für Erstattungen), berechnet Rekomi, welcher Anteil der Provision zurückgeholt wurde, und wendet denselben Anteil auf die Override-Provision an.

  • Volle Erstattung des Verkaufs: Die Override-Provision wird vollständig storniert.
  • Teilerstattung (z. B. 40% des Verkaufsbetrags): Provision und Override-Provision sinken beide um 40%.

Beide Zeilen lösen Webhook-Ereignisse conversion.refunded aus. Wer Einnahmen über die gesamte Laufzeit mitführt, zieht bei beiden Zeilen commissionReversedCents von der laufenden Summe ab.

Ablehnung und Ungültigkeit wirken auf die Override-Zeile

Statusänderungen an der zugrunde liegenden Conversion wirken auf ihre unbezahlte Override-Zeile genauso wie Erstattungen. Die Override-Zeile wird nur angepasst, solange sie noch nicht bezahlt ist; ist eine Override-Provision einmal ausgezahlt, bleibt sie unverändert.

  • Ablehnen. Wird die zugrunde liegende Conversion abgelehnt, wird auch ihre unbezahlte Override-Zeile abgelehnt. Ein abgelehnter Verkauf hinterlässt also keine Einnahmen beim Werber.
  • Für ungültig erklären. Kommt die zugrunde liegende Conversion wegen Betrugsverdachts in Quarantäne, landet auch ihre unbezahlte Override-Zeile in Quarantäne.
  • Validieren. Wird eine zuvor für ungültig erklärte Conversion wiederhergestellt, wird auch die Override-Zeile mit ihrem ursprünglichen Betrag wiederhergestellt.

Webhook-Payloads

conversion.created (Override-Zeile)

Derselbe Envelope wie beim normalen Ereignis conversion.created. Override-Zeilen erkennst du am Feld attributionMethod:

{
  "id": "evt_9f3c1a7b2e4d6f80a1b3c5d7e9f0a2b4",
  "type": "conversion.created",
  "createdAt": "2026-05-12T03:14:25.000Z",
  "organizationId": "b7e2c9a4-3f1d-4e8a-9c2b-6d5f0a1e3c7b",
  "data": {
    "conversionId": "c0nv0override-...",
    "affiliateId": "01234567-A-...",
    "programId": "0789abcd-...",
    "amountCents": 0,
    "currency": "USD",
    "commissionCents": 200,
    "status": "Pending",
    "attributionMethod": "sub_affiliate_override",
    "parentAffiliateConversionId": "c0nv0parent-...",
    "externalEventId": "in_1abc23DEF456:override:3f9c2a1b8e4d6f70a1b3c5d7e9f0a2b4",
    "type": "OneTime"
  }
}

Die externalEventId der Override-Zeile ist die externe Ereignis-ID des zugrunde liegenden Verkaufs mit einem Override-Suffix, das außerdem die ID des Werbers als 32 Hex-Zeichen enthält (:override:<32-hex-recruiter-id>); sehr lange IDs des Verkaufs werden durch ein Hash-Präfix ersetzt. Der Wert bleibt bei erneuten Zustellungen desselben Verkaufsereignisses stabil, du kannst ihn also als Idempotenzschlüssel (idempotency key) nutzen, wenn du Override-Einnahmen erfasst.

conversion.refunded (Override-Zeile)

Wird bei jedem Durchlauf der Weitergabe ausgelöst, in dem RefundedAmountCents der Override-Zeile erhöht wurde. refundedAmountCents und commissionReversedCents sind die Rückholung GENAU DIESES Ereignisses; cumulativeRefundedAmountCents ist die Gesamtsumme der Zeile; isFullRefund ist nur bei dem Durchlauf true, der die Override-Zeile in den Zustand „vollständig erstattet“ gebracht hat. Das Ereignis trägt die Verknüpfung zur Provisionszeile und die Attributionsmethode, damit du Ereignisse von Override-Zeilen gesondert weiterleiten kannst.

{
  "id": "evt_2b4d6f80a1b3c5d7e9f0a2b41c3e5d70",
  "type": "conversion.refunded",
  "createdAt": "2026-05-15T11:00:00Z",
  "organizationId": "b7e2c9a4-3f1d-4e8a-9c2b-6d5f0a1e3c7b",
  "data": {
    "conversionId": "c0nv0override-...",
    "affiliateId": "01234567-A-...",
    "programId": "0789abcd-...",
    "refundedAmountCents": 200,
    "cumulativeRefundedAmountCents": 200,
    "commissionReversedCents": 200,
    "currency": "USD",
    "isFullRefund": true,
    "refundedAt": "2026-05-15T11:00:00Z",
    "parentAffiliateConversionId": "c0nv0parent-...",
    "attributionMethod": "sub_affiliate_override"
  }
}

Warnung für Webhook-Empfänger

Filtert dein Handler Ereignisse conversion.created nach amountCents > 0, um Ereignisse „ohne Umsatz“ auszusortieren, verlierst du stillschweigend alle Override-Ereignisse. Override-Zeilen sind echte Provisionsverpflichtungen mit commissionCents > 0, haben aber immer amountCents = 0.

Bessere Filter:

  • Filtere nach status (z. B. nur bei Approved oder Paid reagieren).
  • Filtere nach commissionCents > 0, wenn du alles willst, wofür der Affiliate Geld bekommt.
  • Prüfe attributionMethod, wenn du Override-Zeilen in eine andere nachgelagerte Verarbeitung leiten willst (z. B. ein eigenes Buchhaltungskonto für Einnahmen der Werber im Unterschied zu Provisionen aus direkten Verkäufen).

Bewerbungsformular: recruitedBy und recruitedByAffiliateId

Der öffentliche Bewerbungsendpunkt (POST /api/p/id/{programId}/apply) nimmt optional einen Verweis auf den Werber an, der am neuen Affiliate-Datensatz die Verknüpfung über eine Rekrutierungsebene herstellt. Es gibt zwei Felder:

  • recruitedBy (String): das aktuelle Feld. Akzeptiert die Affiliate-ID des Werbers als GUID-String, seinen Link-Slug in der Kampagne oder seinen kontoweiten ?via=-Slug.
  • recruitedByAffiliateId (GUID): das ältere Feld. Wird für ältere Integrationen weiterhin akzeptiert.
curl -sS https://api.rekomi.com/api/p/id/0789abcd-.../apply \
  -H "Content-Type: application/json" \
  -d '{
    "email": "newaffiliate@example.com",
    "fullName": "New Affiliate",
    "recruitedBy": "v6media"
  }'

Regeln:

  • Der Verweis muss auf einen freigegebenen (Approved) Affiliate in genau der Kampagne führen, für die die Bewerbung gilt. Nicht auflösbare Werte und Abweichungen werden stillschweigend verworfen (die Bewerbung geht durch, aber RecruitedByAffiliateId bleibt null).
  • Wirbt sich ein Bewerber selbst, wird der Verweis stillschweigend verworfen, nicht abgelehnt: Ist der Bewerber derselbe Clerk-Nutzer wie der Werber oder bewirbt er sich mit derselben normalisierten E-Mail-Adresse, geht die Bewerbung trotzdem durch, nur ohne Verknüpfung zum Werber.
  • Hat die Kampagne enabled = false, wird gar kein Werber verknüpft: Die Bewerbung geht durch, aber es wird kein Werber gespeichert.
  • Die Felder sind aus SEO-Gründen nicht im öffentlichen Schema des Bewerbungsformulars sichtbar; nur Aufrufer, die einen Verweis auf einen Werber haben (meist aus einer markierten URL), sollten sie übergeben.

In der Praxis baust du das nicht von Hand. Die Rekrutierungs-URL (die GET /api/v1/me/sub-affiliate/link liefert) trägt recruited_by={token} als Query-Parameter. Das Token ist der kontoweite ?via=-Slug des Werbers, falls er einen hat, sonst sein Link-Slug in der Kampagne, sonst die GUID seiner Affiliate-ID. Die öffentliche Bewerbungsseite liest diesen Parameter und schickt ihn beim Absenden des Formulars als recruitedBy mit.

MCP-Tools

Für Integrationen mit KI-Agenten gibt es drei Tools, die die Endpunkte für Marken kapseln:

ToolEntspricht
get_program_sub_affiliate_configGET /api/v1/programs/{id}/sub-affiliate-config
set_program_sub_affiliate_configPUT /api/v1/programs/{id}/sub-affiliate-config
list_affiliate_sub_affiliatesGET /api/v1/affiliates/{id}/sub-affiliates

Alle drei akzeptieren entweder rk_live_* (direkter API-Schlüssel) oder rk_mcp_* (weitergeleitet über mcp.rekomi.com). Die Endpunkte /me/sub-affiliate/* auf der Seite der Affiliates funktionieren nur mit Clerk-JWT und sind bewusst nicht über MCP erreichbar (die Weiterleitung trägt die Identität der Markenorganisation, nicht die eines einzelnen Affiliates). Das Authentifizierungsmodell beschreibt die Seite MCP-Server.

Siehe auch

  • Sub-Affiliate-Recruiting (Marken): Konzept, Rechenbeispiel, Weitergabe von Erstattungen, FAQ.
  • Conversion-Währung: Override-Zeilen tragen dasselbe Feld currency; die Override-Provision lautet auf die Währung des zugrunde liegenden Verkaufs.
  • Webhooks: Envelope der Ereignisse, Prüfung der Signatur, Verhalten bei Wiederholungen.
  • API-Referenz: knappe Endpunkt-Signaturen neben dem Rest von /api/v1/*.