---
title: Wywołania zwrotne | RunAPI
description: Bezpiecznie odbieraj i weryfikuj dostarczenia wywołań zwrotnych zadania.
url: https://runapi.ai/pl/docs/guides/task-api/callbacks.md
canonical: https://runapi.ai/pl/docs/guides/task-api/callbacks
locale: pl
---

> Wersja HTML: https://runapi.ai/pl/docs/guides/task-api/callbacks
> Indeks witryny dla agentów: https://runapi.ai/llms.txt

# Wywołania zwrotne

Używaj wywołań zwrotnych, aby odbierać zdarzenia cyklu życia Zadania (Task) pod publicznym punktem końcowym HTTPS. Weryfikuj każde wywołanie zwrotne przed przetworzeniem jego treści JSON, aby tylko dostarczenia podpisane dla Twojego konta mogły zmieniać stan aplikacji.

## Konfiguracja adresu URL wywołania zwrotnego

Dodaj publiczny adres HTTPS `callback_url` podczas tworzenia zadania (Task).
Treść zdarzenia i stany cyklu życia zależą od punktu końcowego; zapoznaj się
z dokumentacją interfejsu API danego punktu końcowego, aby poznać ładunki
wywołań zwrotnych.

```json
{
  "model": "flux-2-pro-text-to-image",
  "prompt": "A product photograph on a clean studio background",
  "callback_url": "https://your-domain.com/webhooks/runapi"
}
```

## Tworzenie tajnego klucza wywołania zwrotnego

Postępuj zgodnie z [Przewodnikiem po uwierzytelnianiu](https://runapi.ai/pl/docs/guides/authentication.md), aby się zalogować,
a następnie otwórz sekcję Klucze API i utwórz Callback Secret dla konta, które
tworzy zadanie (Task). Przechowuj wartość w menedżerze sekretów i udostępniaj ją
wyłącznie odbiorcy wywołań zwrotnych. Nie jest to klucz API i nigdy nie wolno go wysyłać w żądaniu Task.

Sekret podpisuje wywołania zwrotne dla danego konta. Jego rotacja zmienia sygnaturę dla późniejszych dostaw, dlatego natychmiast zaktualizuj każdy odbiornik wywołań zwrotnych i przechowuj obie wartości tylko przez czas niezbędny do obsługi dostarczeń w toku.

## Weryfikuj podpis wywołania zwrotnego

Każde wywołanie zwrotne to HTTP `POST` z nagłówkiem `Content-Type: application/json`.
RunAPI nie dodaje nagłówka `Authorization` do tego żądania. Zweryfikuj
następujące nagłówki przed deserializacją treści:

| Nagłówek | Znaczenie |
|----------
| `X-Callback-Id` | Unikalny identyfikator tej próby dostarczenia. |
| `X-Callback-Timestamp` | Znacznik czasu Unix w sekundach określający moment podpisania dostarczenia. |
| `X-Callback-Signature` | Podpis HMAC-SHA-256 zakodowany w Base64. |

Zbuduj podpisaną wartość dokładnie w następujący sposób, używając niezmodyfikowanych bajtów treści żądania:

```text
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
```

Zdekoduj Callback Secret z Base64, oblicz HMAC-SHA-256 na tej
wartości, zakoduj wynik w Base64 i porównaj go z
`X-Callback-Signature` przy użyciu porównania odpornego na ataki czasowe. Nie parsuj i
nie serializuj ponownie JSON przed weryfikacją.

### JavaScript

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyCallback({headers, rawBody, callbackSecret}) {
  const callbackId = headers["x-callback-id"];
  const timestamp = Number(headers["x-callback-timestamp"]);
  const signature = headers["x-callback-signature"];

  if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
  const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
    .update(signedContent, "utf8")
    .digest();
  const received = Buffer.from(signature, "base64");

  return expected.length === received.length && timingSafeEqual(expected, received);
}
```

Przekaż surowy ciąg treści żądania ze środowiska do `rawBody`; nie wywołuj
`JSON.stringify` na przetworzonych danych.

### Python

```python
import base64
import hashlib
import hmac
import time


def verify_callback(headers, raw_body, callback_secret):
    callback_id = headers.get("X-Callback-Id")
    timestamp = headers.get("X-Callback-Timestamp")
    signature = headers.get("X-Callback-Signature")

    if not callback_id or not timestamp or not signature:
        return False

    try:
        timestamp = int(timestamp)
        secret = base64.b64decode(callback_secret, validate=True)
        received = base64.b64decode(signature, validate=True)
    except (ValueError, TypeError):
        return False

    if abs(time.time() - timestamp) > 300:
        return False

    signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
    expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
    return hmac.compare_digest(expected, received)
```

Przekaż dokładny surowy ciąg treści żądania odebrany przez Twoje środowisko HTTP
jako `raw_body`.

## Bezpieczne przetwarzanie dostaw

* Zwróć odpowiedź `2xx` dopiero po zaakceptowaniu wywołania zwrotnego do przetworzenia.
  Po odpowiedzi innej niż `2xx` lub awarii transportu dostarczenie jest ponawiane
  do 10 razy.
* Odpowiedz w ciągu 15 sekund. Wolniejsze zadania umieszczaj w kolejce po weryfikacji,
  zamiast blokować odpowiedź HTTP.
* Odrzucaj wywołania zwrotne z brakującymi nagłówkami podpisu, nieprawidłowym podpisem
  lub znacznikiem czasu poza oknem tolerancji zdefiniowanym przez odbiornik.

## Rozwiązywanie problemów z weryfikacją

* **Niezgodność sygnatury:** upewnij się, że Callback Secret należy do tego samego konta co Zadanie, zdekoduj go za pomocą Base64 i podpisz oryginalną treść, a nie przeanalizowany JSON.
* **Brakujące nagłówki sygnatury:** utwórz Callback Secret przed poleganiem na wywołaniach zwrotnych w przypadku zmian stanu.
* **Znacznik czasu odrzucony:** zsynchronizuj zegar odbiornika i użyj tolerancji odpowiedniej dla swojego wdrożenia.

W celu uzyskania wskazówek dotyczących konfiguracji i cyklu życia wróć do [Szybkiego startu
Task API](https://runapi.ai/pl/docs/guides/task-api/quickstart.md).

---

## Więcej od RunAPI

- [Strona główna](https://runapi.ai/pl/.md)
- [Katalog modeli](https://runapi.ai/pl/models.md)
- [Cennik](https://runapi.ai/pl/pricing.md)
- [Dostawcy](https://runapi.ai/pl/models)
- [Dokumentacja](https://runapi.ai/pl/docs/guides)
- [SDK](https://runapi.ai/pl/sdk.md)
- [CLI](https://runapi.ai/pl/cli.md)
- [Serwer MCP](https://runapi.ai/pl/mcp.md)
- [Claude Code vs Cursor](https://runapi.ai/pl/claude-code-vs-cursor.md)
- [Konfiguracja Cursor API](https://runapi.ai/pl/cursor-api-setup.md)
- [RunAPI vs OpenRouter](https://runapi.ai/pl/openrouter-alternative.md)
- [Enterprise](https://runapi.ai/pl/contact.md)
- [Kontakt](https://runapi.ai/pl/contact.md)
- [Regulamin](https://runapi.ai/pl/terms.md)
- [Prywatność](https://runapi.ai/pl/privacy.md)
- [Indeks witryny dla agentów](https://runapi.ai/llms.txt)

Kontakt: contact@runapi.ai

## Dane strukturalne

```json
[
  {
    "@context": "https://schema.org",
    "inLanguage": "pl",
    "@type": "WebSite",
    "name": "RunAPI",
    "url": "https://runapi.ai/pl",
    "potentialAction": {
      "@type": "SearchAction",
      "target": {
        "@type": "EntryPoint",
        "urlTemplate": "https://runapi.ai/pl/models?q={search_term_string}"
      },
      "query-input": "required name=search_term_string"
    }
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "pl",
    "@type": "Organization",
    "name": "RunAPI",
    "url": "https://runapi.ai/pl",
    "logo": {
      "@type": "ImageObject",
      "url": "https://runapi.ai/plicon.svg"
    },
    "sameAs": [
      "https://github.com/runapi-ai"
    ]
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "pl",
    "@type": "TechArticle",
    "headline": "Wywołania zwrotne",
    "description": "Bezpiecznie odbieraj i weryfikuj dostarczenia wywołań zwrotnych zadania.",
    "url": "https://runapi.ai/pl/docs/guides/task-api/callbacks",
    "mainEntityOfPage": "https://runapi.ai/pl/docs/guides/task-api/callbacks"
  }
]
```
