콜백
Task 콜백 전달을 안전하게 수신하고 확인합니다.
공개 HTTPS 엔드포인트에서 Task 수명 주기 이벤트를 수신하려면 콜백을 사용하세요. JSON 본문을 처리하기 전에 모든 콜백을 검증하여 계정에 서명된 전달만이 애플리케이션 상태를 변경할 수 있도록 하세요.
콜백 URL 구성
Task를 생성할 때 공개 HTTPS callback_url을 추가합니다. 이벤트 본문과 생명주기 상태는 엔드포인트에 따라 다르며, 콜백 페이로드에 대한 자세한 내용은 해당 엔드포인트의 API 참조를 확인하십시오.
{
"model": "flux-2-pro-text-to-image",
"prompt": "A product photograph on a clean studio background",
"callback_url": "https://your-domain.com/webhooks/runapi"
}
Callback Secret 만들기
인증 가이드에 따라 로그인한 후 API 키를 열고 Task를 생성하는 계정에 대한 콜백 시크릿을 생성하세요. 값을 시크릿 매니저에 저장하고 콜백 수신기에서만 사용할 수 있도록 하세요. 이것은 API 키가 아니며 Task 요청에 절대 전송해서는 안 됩니다.
비밀은 해당 계정의 콜백에 서명합니다. 비밀을 교체하면 이후 전달의 서명이 변경되므로, 모든 콜백 수신자를 즉시 업데이트하고, 진행 중인 전달을 처리하는 데 필요한 시간 동안만 두 값을 모두 사용할 수 있는 상태로 유지하세요.
콜백 서명 확인
각 콜백은 Content-Type: application/json을 가진 HTTP POST입니다.
RunAPI는 이 요청에 Authorization 헤더를 추가하지 않습니다. 본문을 역직렬화하기 전에 다음 헤더를 확인하세요:
X-Callback-Id
이번 전송 시도에 대한 고유 식별자.
X-Callback-Timestamp
전송이 서명된 시점의 Unix 타임스탬프(초 단위).
X-Callback-Signature
Base64로 인코딩된 HMAC-SHA-256 서명.
수정되지 않은 요청 본문 바이트를 사용하여 다음과 같이 정확하게 서명 값을 작성하십시오:
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
Callback Secret을 Base64로 디코딩하고, 해당 값에 대해 HMAC-SHA-256을 계산한 후 결과를
Base64로 인코딩하여 타이밍 안전 비교 방식으로
X-Callback-Signature와 비교하십시오. 검증 전에 JSON을 파싱하거나
재직렬화하지 마십시오.
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);
}
프레임워크의 원시 요청 본문 문자열을 rawBody에 전달하세요. 파싱된 데이터에
JSON.stringify를 호출하지 마세요.
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)
HTTP 프레임워크가 수신한 정확한 원시 요청 본문 문자열을
raw_body로 전달하세요.
안전한 전달 처리
- 콜백이 처리 대기 중으로 수락된 후에만
2xx응답을 반환하십시오.2xx가 아닌 응답이나 전송 실패 후에는 최대 10회까지 재전송을 시도합니다. - 15초 이내에 응답하십시오. 처리 속도가 느린 작업은 HTTP 응답을 차단하는 대신 검증 후 큐에 넣으십시오.
- 서명 헤더가 누락되었거나, 서명이 유효하지 않거나, 타임스탬프가 수신기에서 정의한 허용 범위를 벗어난 콜백은 거부하십시오.
검증 문제 해결
- 서명 불일치: Callback Secret이 작업과 동일한 계정에 속하는지 확인하고, Base64로 디코딩한 후 파싱된 JSON이 아닌 원본 바디에 서명하세요.
- 서명 헤더 누락: 상태 변경에 콜백을 사용하기 전에 Callback Secret을 생성하세요.
- 타임스탬프 거부됨: 수신자의 클럭을 동기화하고 배포 환경에 적합한 허용 오차를 사용하세요.
설정 및 수명 주기 안내에 대해서는 Task API 빠른 시작으로 돌아가세요.