dealsky.ioDocs
Zur App
API-Referenz

Medien

Bilder, Videos und Audio hochladen und verwalten

#

Bild hochladen

POST/v1/media/images
Scope write:assetsRecht: Outreach Plattformschreibt

Lädt ein Bild zu Cloudflare Images hoch und legt es in der Medienbibliothek an, wie das Hochladen unter Assets, Bilder in der App. Danach steht es dort mit Name und Art (Bild, Logo, Icon) bereit, url ist sofort öffentlich abrufbar. Kostet keine Credits. Jeder Aufruf legt ein neues Bild an.

Genau eines von source_url oder data angeben:

  • source_url: öffentliche https-Adresse der Bilddatei. Cloudflare holt die Datei selbst ab, dealsky lädt nichts herunter. Adressen mit IP statt Hostname, mit Zugangsdaten, localhost, .local und .internal werden abgelehnt. Typ und Größe prüft Cloudflare beim Abholen (höchstens 10 MB); ist die Datei kein Bild, zu groß oder nicht erreichbar, kommt 422 mit dem Grund. Der empfohlene Weg für alles über etwa 700 KB.
  • data: Base64 oder data-URL (data:image/png;base64,…). Weil der ganze Body höchstens 1 MB groß sein darf, passen so Bilder bis etwa 700 KB. Der Typ wird am Dateiinhalt erkannt (JPEG, PNG, WebP, SVG wie in der App, kein GIF); ein abweichender content_type wird abgelehnt. SVG mit Skripten, Event-Attributen (onload= …), javascript:-Links oder eingebetteten Inhalten wird abgelehnt.

category wie in der App: logos, icons, images oder pictures. Profilbilder (Avatar) gehören zu einer Person und gehen nicht über die API.

Mit Test-Key wird alles geprüft (Felder, Adresse, Typ, Größe), aber nichts hochgeladen und nichts angelegt.

Body

Genau eines von source_url oder data.

  • source_urlstring (uri)max. 2048 Zeichen

    https-Adresse der Bilddatei; Cloudflare holt sie ab

  • datastring

    Bild als Base64 oder data-URL; der Body ist auf 1 MB begrenzt

  • categorystringPflicht

    Bereich in der Bibliothek: logos, icons, images, pictures

    logos images icons pictures
  • file_namestringmax. 200 Zeichen

    Anzeigename; fließt bereinigt in die Bild-ID ein

  • content_typestring

    Nur mit data: angegebener Typ, muss zum Inhalt passen

    image/jpeg image/png image/webp image/svg+xml

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING409 CONFLICT429 RATE_LIMITED
curl -X POST "https://api.dealsky.io/functions/v1/api/v1/media/images" \
  -H "X-API-Key: $DEALSKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "source_url": "https://www.beispiel.de/assets/logo-beispiel.png",
  "category": "logos"
}'
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/images", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "source_url": "https://www.beispiel.de/assets/logo-beispiel.png",
    "category": "logos"
  }),
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "POST",
    "https://api.dealsky.io/functions/v1/api/v1/media/images",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
    json={
        "source_url": "https://www.beispiel.de/assets/logo-beispiel.png",
        "category": "logos"
    },
)
print(res.json())
Antwort 201
{
  "ok": true,
  "data": {
    "id": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a",
    "url": "https://imagedelivery.net/Xk3bQ9cR7tLm2pWv8yZa1g/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/logos/1760781120000_9f2c1a7b_logo-beispiel.png/public",
    "cf_image_id": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/logos/1760781120000_9f2c1a7b_logo-beispiel.png",
    "type": "logo",
    "category": "logos",
    "name": "logo-beispiel.png",
    "created_at": "2026-10-18T10:12:00.000Z"
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}
#

Medien auflisten

GET/v1/media
Scope read:assetsRecht: Videosliest

Bilder, Logos, Icons, Videos und Sprachnachrichten aus der Medienbibliothek, wie sie in der App unter Assets (Videos und Bilder, Sprachnachrichten) stehen, neueste zuerst. Gelöschte Einträge fehlen wie in der App. Landingpage-Vorlagen stehen nicht hier, sondern unter GET /v1/landing-page-templates. Von dealsky mitgelieferte System-Videos, die die App zusätzlich zeigt, liefert die API nicht.

Filter: kind fasst die Typen zusammen: image (image, logo, icon), video (static_video und die älteren hauptvideo, sprachsync_video, video; dealsky behandelt sie seit September 2026 als eine Videoart), audio (audio, voice). type filtert auf einzelne Typen. Beides kommagetrennt, z. B. kind=image,audio. q sucht im Namen.

Sichtbarkeit wie in der App: Mit dem Recht outreach sieht die Person, der der Key gehört, alles. Mit nur outreach.videos (Mitarbeiter, die eigene Videos aufnehmen) sieht sie nur Videos und davon nur die eigenen. Fragt so ein Key ausdrücklich nach Bildern oder Audio, kommt 403 mit details.required_permission = "outreach".

url ist die öffentliche Adresse, mit der die App die Datei zeigt oder abspielt. Speicherpfade und interne Angaben gibt die API nicht heraus.

Query-Parameter

  • limitintegerab 1bis 100

    Einträge pro Seite (Standard 25, höchstens 100)

  • cursorstringmax. 200 Zeichen

    Wert aus meta.next_cursor der vorigen Seite

  • kindListe aus string

    image, video, audio; kommagetrennt

    image video audio
  • typeListe aus string

    Einzelne Typen, kommagetrennt, z. B. logo,icon

    image logo icon static_video hauptvideo sprachsync_video video audio voice
  • qstringmax. 200 Zeichen

    Suche im Namen (Teilstring, Groß/Klein egal)

Felder der Antwort
  • idstring (uuid)

    ID in der Medienbibliothek

  • namestring

    Anzeigename wie in der App

  • typestring

    Typ in der Bibliothek. Neue Videos haben static_video, ältere auch hauptvideo, sprachsync_video oder video

    image logo icon static_video hauptvideo sprachsync_video video audio voice
  • kindstring

    Art: image (Bild, Logo, Icon), video, audio (Sprachnachricht)

    image video audio
  • urlstring, kann null sein

    Öffentliche Adresse, mit der die App die Datei zeigt oder abspielt (Bilder bei Cloudflare Images, Videos und Audio auf cdn.dealskycloud.com)

  • thumbnail_urlstring, kann null sein

    Vorschaubild eines Videos. Bei Bildern ist url selbst das Bild

  • descriptionstring, kann null sein

    Beschreibung (bei Videos in der App pflegbar)

  • duration_secondsnumber, kann null sein

    Länge in Sekunden bei Videos und Sprachnachrichten, falls beim Hochladen gemessen

  • size_mbnumber, kann null sein

    Dateigröße in MB, falls gespeichert (bei Sprachnachrichten)

  • is_defaultboolean

    In der App als Standard markiert (Stern bei Logos und Icons)

  • created_atstring (date-time)

    Zeitpunkt, an dem das Medium in der Bibliothek angelegt wurde

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING429 RATE_LIMITED
curl -X GET "https://api.dealsky.io/functions/v1/api/v1/media" \
  -H "X-API-Key: $DEALSKY_API_KEY"
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media", {
  method: "GET",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
  },
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "GET",
    "https://api.dealsky.io/functions/v1/api/v1/media",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
)
print(res.json())
Antwort 200
{
  "ok": true,
  "data": [
    {
      "id": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a",
      "name": "logo-beispiel.png",
      "type": "logo",
      "kind": "image",
      "url": "https://imagedelivery.net/Xk3bQ9cR7tLm2pWv8yZa1g/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/logos/1760781120000_9f2c1a7b_logo-beispiel.png/public",
      "thumbnail_url": null,
      "description": null,
      "duration_seconds": null,
      "size_mb": null,
      "is_default": true,
      "created_at": "2026-10-18T10:12:00.000Z"
    },
    {
      "id": "7b8c9d0e-1f2a-4b3c-9d4e-5f6a7b8c9d0e",
      "name": "Sprachnachricht · 14.10. 09:12",
      "type": "audio",
      "kind": "audio",
      "url": "https://cdn.dealskycloud.com/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/documents/audio/1760425920000_sprachnachricht.m4a",
      "thumbnail_url": null,
      "description": null,
      "duration_seconds": 23,
      "size_mb": 0.37,
      "is_default": false,
      "created_at": "2026-10-14T07:12:00.000Z"
    },
    {
      "id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
      "name": "Vorstellung Geschäftsführung",
      "type": "static_video",
      "kind": "video",
      "url": "https://cdn.dealskycloud.com/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760258400000_vorstellung.mp4",
      "thumbnail_url": "https://imagedelivery.net/Xk3bQ9cR7tLm2pWv8yZa1g/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/images/images/1760258460000_vorstellung-vorschau.jpg/public",
      "description": "Kurzes Intro für Landingpages und LinkedIn",
      "duration_seconds": 74,
      "size_mb": null,
      "is_default": false,
      "created_at": "2026-10-12T08:41:00.000Z"
    }
  ],
  "meta": {
    "request_id": "req_7f3a…",
    "next_cursor": null,
    "has_more": false
  }
}
#

Ein Medium abrufen

GET/v1/media/{id}
Scope read:assetsRecht: Videosliest

Ein Eintrag der Medienbibliothek mit denselben Feldern wie in der Liste. 404, wenn es die ID im Konto nicht gibt, der Eintrag gelöscht ist oder keine Mediendatei ist (eine Landingpage-Vorlage steht unter GET /v1/landing-page-templates/{id}). Mit nur dem Recht outreach.videos ergeben fremde Videos 404 und Bilder oder Sprachnachrichten 403 mit details.required_permission = "outreach", wie in der App.

Pfad-Parameter

  • idstring (uuid)Pflicht

    ID des Mediums

Felder der Antwort
  • idstring (uuid)

    ID in der Medienbibliothek

  • namestring

    Anzeigename wie in der App

  • typestring

    Typ in der Bibliothek. Neue Videos haben static_video, ältere auch hauptvideo, sprachsync_video oder video

    image logo icon static_video hauptvideo sprachsync_video video audio voice
  • kindstring

    Art: image (Bild, Logo, Icon), video, audio (Sprachnachricht)

    image video audio
  • urlstring, kann null sein

    Öffentliche Adresse, mit der die App die Datei zeigt oder abspielt (Bilder bei Cloudflare Images, Videos und Audio auf cdn.dealskycloud.com)

  • thumbnail_urlstring, kann null sein

    Vorschaubild eines Videos. Bei Bildern ist url selbst das Bild

  • descriptionstring, kann null sein

    Beschreibung (bei Videos in der App pflegbar)

  • duration_secondsnumber, kann null sein

    Länge in Sekunden bei Videos und Sprachnachrichten, falls beim Hochladen gemessen

  • size_mbnumber, kann null sein

    Dateigröße in MB, falls gespeichert (bei Sprachnachrichten)

  • is_defaultboolean

    In der App als Standard markiert (Stern bei Logos und Icons)

  • created_atstring (date-time)

    Zeitpunkt, an dem das Medium in der Bibliothek angelegt wurde

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING404 NOT_FOUND429 RATE_LIMITED
curl -X GET "https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10" \
  -H "X-API-Key: $DEALSKY_API_KEY"
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10", {
  method: "GET",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
  },
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "GET",
    "https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
)
print(res.json())
Antwort 200
{
  "ok": true,
  "data": {
    "id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
    "name": "Vorstellung Geschäftsführung",
    "type": "static_video",
    "kind": "video",
    "url": "https://cdn.dealskycloud.com/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760258400000_vorstellung.mp4",
    "thumbnail_url": "https://imagedelivery.net/Xk3bQ9cR7tLm2pWv8yZa1g/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/images/images/1760258460000_vorstellung-vorschau.jpg/public",
    "description": "Kurzes Intro für Landingpages und LinkedIn",
    "duration_seconds": 74,
    "size_mb": null,
    "is_default": false,
    "created_at": "2026-10-12T08:41:00.000Z"
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}
#

Medium aus der Bibliothek entfernen

DEL/v1/media/{id}
Scope write:assetsRecht: Videosschreibt

Entfernt ein Bild, Video oder eine Sprachnachricht aus der Medienbibliothek. Danach fehlt es in jeder Auswahl der App und in GET /v1/media. Die Datei selbst bleibt erhalten, darum zeigen ältere Nachrichten, Landingpages und Vorlagen weiter darauf. Kostet nichts.

Wird das Medium noch verwendet, bleibt es stehen und es kommt 409 mit details.used_by (Liste aus type, id, name). Geprüft wird wie in der App: Videos in laufenden oder pausierten Kampagnen (als Sprecher-Video) und aktiven Landingpages, Sprachnachrichten in laufenden Kampagnen, Bilder als Logo in Landingpages oder als Firmenlogo. Vorlagen sperren wie in der App nicht.

Rechte wie in der App: Bilder und Sprachnachrichten nur mit outreach. Mit nur outreach.videos lassen sich eigene Videos entfernen; fremde ergeben 404.

Mit Test-Key wird alles geprüft (auch die Verwendung), aber nichts entfernt.

Pfad-Parameter

  • idstring (uuid)Pflicht

    ID des Mediums

Felder der Antwort
  • idstring (uuid)

    ID des entfernten Mediums

  • kindstring

    Art: image (Bild, Logo, Icon), video, audio (Sprachnachricht)

    image video audio
  • typestring

    Typ in der Bibliothek, z. B. static_video, audio, logo

  • archivedboolean

    Immer true: das Medium ist aus der Bibliothek entfernt, die Datei selbst bleibt erhalten

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING404 NOT_FOUND429 RATE_LIMITED
curl -X DELETE "https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10" \
  -H "X-API-Key: $DEALSKY_API_KEY"
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10", {
  method: "DELETE",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
  },
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "DELETE",
    "https://api.dealsky.io/functions/v1/api/v1/media/5b0c1e7a-3f1d-4a52-9c1e-8a7d2b6f4e10",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
)
print(res.json())
Antwort 200
{
  "ok": true,
  "data": {
    "id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
    "kind": "video",
    "type": "static_video",
    "archived": true
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}
#

Video oder Audio hochladen (Adresse holen)

POST/v1/media/uploads
Scope write:assetsRecht: Videosschreibt

Erster Schritt für Videos und Sprachnachrichten. Liefert eine vorsignierte Adresse, an die die Datei direkt per HTTP PUT geht (nicht über die API, deren Body auf 1 MB begrenzt ist), wie das Hochladen in der App. Danach r2_path an POST /v1/media/videos bzw. POST /v1/media/audio übergeben. Kostet keine Credits. Erst der zweite Schritt legt etwas in der Bibliothek an.

So geht es weiter: PUT {upload_url} mit genau den Headern aus upload_headers und der Datei als Body, innerhalb von 24 Stunden (expires_at). Antwortet der Speicher mit 200, liegt die Datei bereit.

Erlaubt wie in der App: Video als .mp4 (video/mp4), .mov (video/quicktime) oder .webm (video/webm) bis 1 GB; jedes Video wird danach in MP4 gewandelt. Audio als .m4a oder .mp4 (audio/mp4) bis 20 MB, das Format, das LinkedIn für Sprachnachrichten verlangt. Andere Audio-Formate (MP3, WAV, OGG) wandelt die App beim Hochladen um und wartet darauf; über die API bitte vorher in M4A umwandeln. content_type muss zur Endung von file_name passen, size_bytes ist die Größe der Datei.

Rechte wie in der App: Videos mit outreach.videos (Medienseite), Sprachnachrichten nur mit outreach (Seite Sprachnachrichten). Ohne outreach kommt bei kind=audio 403 mit details.required_permission = "outreach".

Mit Test-Key wird alles geprüft, aber keine Adresse ausgestellt (would_presign).

Body

  • kindstringPflicht

    video oder audio (Sprachnachricht)

    video audio
  • file_namestringPflichtmax. 200 Zeichen

    Dateiname mit Endung; fließt bereinigt in den Speicherort ein

  • content_typestringPflicht

    Typ der Datei, passend zur Endung

    video/mp4 video/quicktime video/webm audio/mp4
  • size_bytesintegerPflichtab 1bis 1073741824

    Größe der Datei in Byte

Felder der Antwort
  • kindstring

    Art des Uploads wie angefragt: video oder audio (Sprachnachricht)

    video audio
  • r2_pathstring

    Speicherort der Datei. Nach dem Hochladen unverändert an POST /v1/media/videos bzw. POST /v1/media/audio übergeben

  • upload_urlstring

    Vorsignierte Adresse: die Datei per HTTP PUT als Body dorthin schicken. Nicht weitergeben, sie erlaubt das Schreiben dieser einen Datei

  • upload_methodstring

    HTTP-Methode für das Hochladen an upload_url, immer PUT

    PUT
  • upload_headersobject

    Header, die der PUT genau so tragen muss (Content-Type ist Teil der Signatur)

  • public_urlstring

    Öffentliche Adresse der Rohdatei nach dem Hochladen

  • expires_atstring (date-time)

    Bis dahin gilt upload_url (24 Stunden, wie in der App)

  • max_size_bytesinteger

    Höchstgröße der Datei für diese Art

  • next_stepstring

    Der Aufruf nach dem Hochladen

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING409 CONFLICT429 RATE_LIMITED
curl -X POST "https://api.dealsky.io/functions/v1/api/v1/media/uploads" \
  -H "X-API-Key: $DEALSKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "kind": "video",
  "file_name": "vorstellung.mp4",
  "content_type": "video/mp4",
  "size_bytes": 48234112
}'
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/uploads", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "kind": "video",
    "file_name": "vorstellung.mp4",
    "content_type": "video/mp4",
    "size_bytes": 48234112
  }),
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "POST",
    "https://api.dealsky.io/functions/v1/api/v1/media/uploads",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
    json={
        "kind": "video",
        "file_name": "vorstellung.mp4",
        "content_type": "video/mp4",
        "size_bytes": 48234112
    },
)
print(res.json())
Antwort 200
{
  "ok": true,
  "data": {
    "kind": "video",
    "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4",
    "upload_url": "https://4f2a9c1e7b3d5a8f0e6c2b4d9a7f1e3c.r2.cloudflarestorage.com/dealskyvideos/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4?X-Amz-Date=20261018T101200Z&X-Amz-Expires=86400&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=2c9e4f1a7b3d5e8c%2F20261018%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=5d0f3c2a9e8b7a6f5e4d3c2b1a0f9e8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f",
    "upload_method": "PUT",
    "upload_headers": {
      "Content-Type": "video/mp4"
    },
    "public_url": "https://cdn.dealskycloud.com/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4",
    "expires_at": "2026-10-19T10:12:00.000Z",
    "max_size_bytes": 1073741824,
    "next_step": "POST /v1/media/videos"
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}
#

Hochgeladenes Video in MP4 wandeln und anlegen

POST/v1/media/videos
Scope write:assetsRecht: Videosschreibt

Zweiter Schritt nach POST /v1/media/uploads mit kind=video und dem PUT der Datei. Startet die Umwandlung in MP4 auf dem Server, wie die App es nach jeder Aufnahme tut (Videos müssen MP4 mit Längenangabe sein, sonst scheitern spätere Video-Nachrichten). Ist sie fertig, steht das Video in der Bibliothek (static_video, wie ein Upload in der App) und es gibt eine Benachrichtigung in der Glocke. Kostet keine Credits.

Antwort 202 mit job_id. Den Stand liefert GET /v1/jobs/{id} (kind video_conversion, braucht das Recht outreach); bei succeeded steht die ID des neuen Videos in result.asset_id. Mit nur dem Recht outreach.videos erscheint das fertige Video in GET /v1/media?kind=video. Die Umwandlung dauert meist unter einer Minute, bei großen Dateien länger.

Die Datei wird beim Start nicht geprüft. Fehlt sie (PUT nicht erfolgt oder abgelaufen), endet der Auftrag mit failed. Ist sie kein lesbares Video, endet die Umwandlung mit einem Fehler; wie bei Aufnahmen in der App legt dealsky die Rohdatei dann nach etwa 15 Minuten ungewandelt als Video an. Das Video wird auf höchstens 720p verkleinert. Ein Vorschaubild setzt die API nicht, das geht in der App.

r2_path muss aus einem eigenen Upload stammen, sonst 400. Für dieselbe Datei startet nur ein Auftrag: läuft er noch oder ist er fertig, kommt 409 mit details.job_id; nach failed ist ein neuer Versuch möglich.

Mit Test-Key wird alles geprüft, aber nichts gestartet.

Body

  • r2_pathstringPflichtmind. 10 Zeichenmax. 300 Zeichen

    r2_path aus POST /v1/media/uploads

  • namestringPflichtmax. 200 Zeichen

    Anzeigename in der Bibliothek

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING409 CONFLICT429 RATE_LIMITED
curl -X POST "https://api.dealsky.io/functions/v1/api/v1/media/videos" \
  -H "X-API-Key: $DEALSKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4",
  "name": "Vorstellung Geschäftsführung"
}'
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/videos", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4",
    "name": "Vorstellung Geschäftsführung"
  }),
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "POST",
    "https://api.dealsky.io/functions/v1/api/v1/media/videos",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
    json={
        "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4",
        "name": "Vorstellung Geschäftsführung"
    },
)
print(res.json())
Antwort 202
{
  "ok": true,
  "data": {
    "job_id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
    "kind": "video_conversion",
    "status": "running",
    "name": "Vorstellung Geschäftsführung",
    "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/videos/static/1760781120000_3f9a2c1d_vorstellung.mp4"
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}
#

Hochgeladene Sprachnachricht anlegen

POST/v1/media/audio
Scope write:assetsRecht: Outreach Plattformschreibt

Zweiter Schritt nach POST /v1/media/uploads mit kind=audio und dem PUT der Datei. Legt die Sprachnachricht in der Bibliothek an, wie das Hochladen unter Assets, Sprachnachrichten in der App. Sie ist sofort in Kampagnen und im Postfach auswählbar. Kostet keine Credits.

r2_path muss aus einem eigenen Audio-Upload stammen (.m4a oder .mp4), sonst 400. Ob die Datei wirklich hochgeladen wurde, prüft die API nicht; bitte erst nach erfolgreichem PUT aufrufen. Dieselbe Datei lässt sich nur einmal anlegen (409 mit details.id).

duration_seconds (Länge, wie die App sie bei Aufnahmen speichert) und size_bytes (füllt size_mb) sind freiwillig. Recht wie die Seite Sprachnachrichten: outreach.

Mit Test-Key wird alles geprüft, aber nichts angelegt.

Body

  • r2_pathstringPflichtmind. 10 Zeichenmax. 300 Zeichen

    r2_path aus POST /v1/media/uploads

  • namestringPflichtmax. 200 Zeichen

    Anzeigename in der Bibliothek

  • duration_secondsnumberab 0bis 3600

    Länge in Sekunden

  • size_bytesintegerab 1bis 20971520

    Größe der Datei in Byte, wie beim Hochladen angegeben

Mögliche Fehler

400 VALIDATION_ERROR401 INVALID_API_KEY402 PLAN_REQUIRED403 SCOPE_MISSING409 CONFLICT429 RATE_LIMITED
curl -X POST "https://api.dealsky.io/functions/v1/api/v1/media/audio" \
  -H "X-API-Key: $DEALSKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/documents/audio/1760781240000_8b2e7d40_begruessung.m4a",
  "name": "Begrüßung Herbst",
  "duration_seconds": 23,
  "size_bytes": 389120
}'
const res = await fetch("https://api.dealsky.io/functions/v1/api/v1/media/audio", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DEALSKY_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/documents/audio/1760781240000_8b2e7d40_begruessung.m4a",
    "name": "Begrüßung Herbst",
    "duration_seconds": 23,
    "size_bytes": 389120
  }),
});
const { ok, data, error } = await res.json();
import os, requests

res = requests.request(
    "POST",
    "https://api.dealsky.io/functions/v1/api/v1/media/audio",
    headers={"X-API-Key": os.environ["DEALSKY_API_KEY"]},
    json={
        "r2_path": "tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/documents/audio/1760781240000_8b2e7d40_begruessung.m4a",
        "name": "Begrüßung Herbst",
        "duration_seconds": 23,
        "size_bytes": 389120
    },
)
print(res.json())
Antwort 201
{
  "ok": true,
  "data": {
    "id": "7b8c9d0e-1f2a-4b3c-9d4e-5f6a7b8c9d0e",
    "name": "Begrüßung Herbst",
    "type": "audio",
    "kind": "audio",
    "url": "https://cdn.dealskycloud.com/tenants/7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/documents/audio/1760781240000_8b2e7d40_begruessung.m4a",
    "thumbnail_url": null,
    "description": null,
    "duration_seconds": 23,
    "size_mb": 0.37,
    "is_default": false,
    "created_at": "2026-10-18T10:14:00.000Z"
  },
  "meta": {
    "request_id": "req_7f3a…"
  }
}