에러 사전
에러 응답에는 무엇이 잘못됐는지와 함께 다음에 무엇을 해야 하는지가 담겨 있습니다.
응답 형태
모든 에러는 최상위 error 객체 하나로 옵니다. 검증 실패든 인증 실패든 형태가 같습니다.
json
{
"error": {
"type": "invalid_request_error",
"code": "refund_exceeds_remaining_amount",
"message": "환불 누계가 원주문 금액을 초과합니다.",
"param": "data.amount",
"hint": "주문 '20260801-000123' 의 남은 환불 가능 금액은 40,000원입니다. GET /v1/orders/{order_id} 로 확인하세요.",
"doc_url": "https://linkfarm.ai/developers/errors#refund_exceeds_remaining_amount",
"request_id": "req_df953ce566e74a9e91a3f6c2",
"retryable": false
}
}hint 가 이 API 의 특징입니다 — 무엇이 틀렸는지에 그치지 않고 다음에 무엇을 하라를 알려줍니다. 위 예시처럼 남은 환불 가능 금액을 숫자로 줍니다.
문의하실 때 request_id 를 알려주시면 해당 요청을 바로 추적할 수 있습니다.
재시도 규칙
retryable 이 true 일 때만 재시도하세요. 4xx 는 요청 자체가 잘못된 것이라 다시 보내도 같은 결과입니다.
Node
// 429·5xx·네트워크 오류만 재시도합니다. 4xx 는 재시도해도 같은 결과입니다.
for (let attempt = 0; attempt < 4; attempt++) {
const res = await fetch(url, init);
if (res.ok) return res.json();
let error;
try {
({ error } = await res.json());
} catch {
// 프록시·로드밸런서가 만든 응답은 JSON 봉투가 아닐 수 있습니다.
// 그때는 상태코드로 판단합니다 — 재시도 규칙(429·5xx)은 동일합니다.
error = {
code: `http_${res.status}`,
message: res.statusText,
retryable: res.status === 429 || res.status >= 500,
};
}
if (!error?.retryable) throw new Error(`[${error.code}] ${error.message}`);
await sleep(2 ** attempt * 250 + Math.random() * 250); // 백오프 + 지터
}코드별 대응
| HTTP | code | 의미 | 대응 |
|---|---|---|---|
| 401 | invalid_api_key | 키가 없거나 형식이 아니거나 폐기됨 | Authorization: Bearer sk_live_… 형식인지, 대시보드에서 발급한 키가 맞는지 확인하세요. |
| 403 | brand_not_active | 키는 유효하지만 브랜드 계정이 정지·폐쇄되었거나 사업자 확인이 거절됨 | 담당자에게 문의하시거나 support@linkfarm.ai 로 연락해 주세요. 이 기간의 주문은 집계되지 않습니다. |
| 403 | event_type_not_allowed_for_publishable_key | 브라우저용 pk_ 키로 주문·환불을 보냄 | 주문·환불·취소는 서버에서 sk_ 키로 보내야 합니다. 브라우저에서는 page.viewed · product.viewed · cart.item_added · order.observed 만 허용됩니다 — 공개 키로 정산 대상 주문을 만들 수 있으면 누구나 매출을 위조할 수 있습니다. |
| 403 | origin_not_allowed | 허용되지 않은 Origin 에서 pk_ 키를 사용 | 브랜드 대시보드의 연동 설정에서 도메인을 등록하세요. 서버에서 호출하신다면 pk_ 가 아니라 sk_ 키를 쓰셔야 합니다. |
| 403 | publishable_key_cannot_read_orders | pk_ 키로 주문 조회를 시도 | 조회는 서버에서 sk_ 키로 하세요. pk_ 는 브라우저 소스에 노출되는 키라 조회를 허용하면 주문·커미션 원장이 그대로 읽힙니다. |
| 404 | wrong_host | 공개 API 호스트가 아닌 곳으로 호출 | base URL 을 openapi.linkfarm.ai(테스트는 openapi.dev.linkfarm.ai)로 바꾸세요. hint 에 현재 요청 호스트가 들어 있습니다. |
| 404 | order_not_found | 환불·취소·확정 대상 주문이 없음 | 먼저 order.paid 로 주문이 인입돼 있어야 합니다. GET /v1/orders/{order_id} 로 확인하세요. |
| 422 | missing_required_field | 이벤트 타입에 필요한 필드 누락 | param 에 어느 필드인지, hint 에 예시 값이 들어 있습니다. |
| 422 | refund_exceeds_remaining_amount | 환불 누계가 원주문 금액을 초과 | hint 가 남은 환불 가능 금액을 숫자로 알려줍니다. 이미 반영된 환불이 있는지 확인하세요. |
| 422 | refund_currency_mismatch | 환불 통화가 원 주문 통화와 다름 | 원 주문과 같은 통화로 보내세요. 통화가 다르면 환산 기준이 없어 금액을 신뢰할 수 없습니다. |
| 422 | missing_fx_rate | KRW 가 아닌데 환율이 없음 | 1 통화단위당 KRW 환율을 함께 보내세요. 이 값이 주문에 고정되어 환불 계산에도 쓰입니다. |
| 422 | unsupported_currency | 지원하지 않는 통화 | 현재 KRW·USD·JPY·EUR·GBP 를 지원합니다. |
| 422 | unknown_event_type | type 값이 목록에 없음 | hint 에 사용 가능한 타입이 나열됩니다. |
| 422 | invalid_datetime | occurred_at 에 UTC 오프셋이 없음 | 반드시 오프셋을 붙이세요(예: 2026-08-01T14:32:18+09:00). 오프셋 없는 값은 해석 기준이 없어 거부됩니다. |
| 422 | occurred_at_out_of_range | occurred_at 이 허용 범위 밖 | 현재 시각 기준 과거 90일 ~ 미래 5분 이내여야 합니다. 90일보다 오래된 건은 support@linkfarm.ai 로 문의해 주세요. |
| 422 | invalid_cursor | 주문 목록 조회의 cursor 값이 올바르지 않음 | 이전 응답의 next_cursor 를 그대로 넣으세요. 첫 페이지라면 생략하세요. |
| 422 | invalid_request_body | 스키마 위반(타입 오류·알 수 없는 필드) | 알 수 없는 필드는 오타를 잡기 위해 거부됩니다. param 이 어느 경로인지 알려줍니다. |
| 409 | idempotency_key_reused | 같은 Idempotency-Key 로 다른 내용을 전송 | 재시도라면 원래와 동일한 본문을 보내고, 다른 요청이라면 새 키를 쓰세요. |
| 429재시도 | rate_limit_exceeded | 요청이 너무 많음 | Retry-After 헤더만큼 기다린 뒤 재시도하세요. 배치는 요청 1건이 아니라 담긴 이벤트 수만큼 집계되니, 배치로 묶어도 한도는 같습니다. |
| 5xx재시도 | temporary_service_error | 일시적 서버 오류 | 지수 백오프로 재시도하세요. 계속되면 request_id 와 함께 문의해 주세요. |
http_{status} 형태의 코드 — 위 목록에 없는 http_404, http_500 같은 코드는 전용 코드가 없는 계층(라우팅·인프라)에서 난 오류를 표준 봉투로 감싼 것입니다. HTTP 상태코드가 그대로 코드가 되며, retryable 은 429·5xx 일 때만 true 입니다. 재시도 규칙은 표와 동일합니다 — retryable 만 보면 됩니다.
배치에서의 param — 일괄 전송(POST /v1/events/batch)에서 개별 이벤트가 실패하면 param 에 몇 번째 이벤트인지가 함께 옵니다. 필드 단위 오류는 경로까지(events[137].data.amount), 이벤트 단위 오류는 인덱스만(events[137]) 옵니다.