이벤트 레퍼런스

모든 이벤트는 POST /v1/events 하나로 보냅니다. type 이 무엇을 하는지 정합니다.

order.paid — 결제 완료

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

결제가 성공한 직후 서버에서 보냅니다. 같은 order_id 를 다시 보내도 중복 집계되지 않습니다 — 이 성질 덕분에 누락 복구가 재전송만으로 끝납니다.

요청
POST https://openapi.linkfarm.ai/v1/events
Authorization: Bearer sk_live_…
Content-Type: application/json

{
  "type": "order.paid",
  "occurred_at": "2026-08-01T14:32:18+09:00",
  "data": {
    "order_id": "20260801-000123",
    "amount": 59000,
    "currency": "KRW",
    "click_ref": "b_8mK3qP",
    "coupon_code": "SUJIN10",
    "items": [
      { "sku": "SERUM-30", "name": "글로우 세럼 30ml",
        "quantity": 1, "amount": 59000 }
    ]
  }
}
응답 · 200 OK
{
  "id": "evt_7c1f2a9d4b3e8a05c6d1f2",
  "object": "event",
  "type": "order.paid",
  "livemode": true,
  "status": "accepted",
  "attribution": {
    "status": "attributed",
    "via": "code"
  },
  "conversion_id": "c6a9373e-88e4-4a71-90e5-fdc55d1a83bf",
  "request_id": "req_df953ce566e74a9e91a3f6c2"
}

data 필드

order_idstring필수

쇼핑몰의 주문번호. 브랜드 안에서 유일해야 합니다(멱등 키로 쓰입니다).

amountinteger필수

할인 적용 후 소비자가 실제 부담한 커미션 대상 상품 금액. 배송비·포인트 충전·상품권·비대상 상품 제외. currency 의 최소단위 (KRW=원, USD=센트).

click_refstring

랜딩 URL 의 lf_click 값. 자사 도메인 쿠키에 저장했다가 보냅니다.

coupon_codestring

크리에이터 할인코드. click_ref 와 둘 다 있으면 코드가 우선합니다.

currencystring

ISO 4217. 생략하면 KRW. KRW 가 아니면 fx_rate 필수.

fx_ratedecimal

1 통화단위당 KRW. 주문에 고정되어 이후 환불도 같은 환율로 계산됩니다.

parent_order_idstring

구독 갱신일 때 최초 결제의 order_id. 귀속을 상속하고 회차가 자동 계산됩니다.

itemsarray

라인아이템(선택). sku · name · quantity · amount.

customer_hashstring

구매자 식별자의 해시. 원문 개인정보는 보내지 마세요 — 이름·이메일·전화·주소는 받지 않습니다.

occurred_at 규칙 — 결제가 실제 일어난 시각(최상위 필드, 선택). 반드시 UTC 오프셋을 붙이세요(예: 2026-08-01T14:32:18+09:00). 오프셋 없는 값은 해석 기준이 없어 422 로 거절됩니다. 허용 범위는 현재 시각 기준 과거 90일 ~ 미래 5분이며, 생략하면 서버 수신 시각으로 기록됩니다.

귀속되지 않은 경우

쿠폰도 클릭 식별자도 없으면 요청은 정상 처리되고 미귀속으로 기록됩니다. 유효한 매출을 버리면 나중에 대조할 근거가 사라지기 때문에 에러로 만들지 않습니다.

응답 · 200 OK
{
  "id": "evt_1b8e0c5a7f2d9e4a3c6b81",
  "object": "event",
  "type": "order.paid",
  "livemode": true,
  "status": "accepted",
  "attribution": {
    "status": "unattributed",
    "via": null
  },
  "conversion_id": null,
  "request_id": "req_a17c93be2d0f4e88b5129d4e"
}

refund.created — 부분환불

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

한 주문에 환불이 여러 번 들어올 수 있습니다.refund_id로 각각을 구분하며 필수입니다 — 없으면 두 번째 환불이 첫 번째와 같은 것으로 취급되어 무시됩니다.

요청
{
  "type": "refund.created",
  "occurred_at": "2026-08-04T10:11:00+09:00",
  "data": {
    "order_id": "20260801-000123",
    "refund_id": "R1",
    "amount": 19000,
    "reason": "부분 반품"
  }
}
응답 · 200 OK
{
  "id": "evt_44a0d7e1c9b3f5028a6d14",
  "object": "event",
  "type": "refund.created",
  "livemode": true,
  "status": "accepted",
  "attribution": { "status": "attributed", "via": "code" },
  "conversion_id": "c6a9373e-88e4-4a71-90e5-fdc55d1a83bf",
  "request_id": "req_5b2e81a4cc76d039fe117a3c"
}

커미션은 환불 금액에 비례해 줄어듭니다. 59,000원 주문의 커미션 11,800원에서 19,000원을 환불하면 3,800원이 역분개됩니다. 부분환불은 주문을 종결시키지 않으며, 환불 누계가 원금에 도달할 때 종결됩니다.

order.cancelled — 전액 취소

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

항상 남은 잔액 전부가 취소됩니다. amount를 보내도 무시됩니다 — 부분 금액을 취소하려면 refund.created를 쓰세요.

요청
{
  "type": "order.cancelled",
  "data": {
    "order_id": "20260801-000123",
    "refund_id": "C1",
    "reason": "고객 요청"
  }
}
응답 · 200 OK
{
  "id": "evt_9f31b6d2e08c74a5b1e3d0",
  "type": "order.cancelled",
  "livemode": true,
  "status": "accepted",
  "attribution": { "status": "attributed", "via": "code" },
  "conversion_id": "c6a9373e-88e4-4a71-90e5-fdc55d1a83bf",
  "request_id": "req_0d7b41fa9e3c825610abe51d"
}

order.confirmed — 구매 확정

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

원천몰의 구매확정을 기록합니다. 상태 확인·대조용이며 지급 일정을 앞당기지 않습니다.

요청
{
  "type": "order.confirmed",
  "data": { "order_id": "20260801-000123" }
}

구독 갱신

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

갱신 결제에는 클릭도 쿠폰도 없습니다. 최초 결제의 주문번호를 실어 보내면 그 귀속을 상속하고 회차가 자동으로 계산됩니다.

요청
{
  "type": "order.paid",
  "data": {
    "order_id": "20260901-000999",
    "amount": 14900,
    "parent_order_id": "20260801-000123"
  }
}
응답 · 200 OK
{
  "id": "evt_2e5c81a09b4f7d3612ca8e",
  "type": "order.paid",
  "livemode": true,
  "status": "accepted",
  "attribution": {
    "status": "attributed",
    "via": "renewal"
  },
  "conversion_id": "8f21b0c4-15da-4e77-9c33-1a02de5b7f90",
  "request_id": "req_c840be15792fa3d0e66cb8f0"
}

attributed_via renewal 로 돌아옵니다. 브랜드가 반복 커미션 기간을 설정했다면 그 회차를 넘긴 갱신은 커미션 0원으로 기록됩니다.

외화 결제

POST/v1/events
https://openapi.linkfarm.ai/v1/eventssk_

KRW 가 아닌 결제는 fx_rate 가 필수입니다. 이 환율은 주문에 고정되며 이후 환불도 같은 환율로 계산됩니다.

요청
{
  "type": "order.paid",
  "data": {
    "order_id": "P-20260801-77",
    "amount": 999,
    "currency": "USD",
    "fx_rate": "1385.5",
    "coupon_code": "SUJIN10"
  }
}
응답 · 200 OK
{
  "id": "evt_63bd0e7a15c92f4b18ad07",
  "type": "order.paid",
  "livemode": true,
  "status": "accepted",
  "attribution": { "status": "attributed", "via": "code" },
  "conversion_id": "3d5f7a91-4c2e-4b08-a6d1-90ff2e4c8b17",
  "request_id": "req_9ac31be07f45d2680e1b2c7d"
}

환불도 원 주문과 같은 통화로 보내야 합니다. USD 주문에 EUR 환불을 보내면 422 로 거절됩니다 — 통화가 다르면 환산 기준이 없어 금액을 신뢰할 수 없습니다.

주문 상태 조회

GET/v1/orders/{order_id}
https://openapi.linkfarm.ai/v1/orders/{order_id}sk_

우리가 인식한 내용을 그대로 돌려줍니다. 자사 원장과 대조하거나, 통합이 제대로 붙었는지 확인할 때 씁니다.

요청
GET https://openapi.linkfarm.ai/v1/orders/20260801-000123
Authorization: Bearer sk_live_…
응답 · 200 OK
{
  "object": "order",
  "order_id": "20260801-000123",
  "livemode": true,
  "status": "pending",
  "amount": 59000,
  "currency": "KRW",
  "original_amount": null,
  "original_currency": null,
  "fx_rate": null,
  "commission_amount": 11800,
  "refunded_amount": 19000,
  "refunded_commission_amount": 3800,
  "remaining_amount": 40000,
  "attributed": true,
  "attributed_via": "code",
  "parent_order_id": null,
  "occurred_at": "2026-08-01T05:32:18Z",
  "confirm_at": "2026-09-06T15:00:00Z"
}

일괄 전송 (대사)

POST/v1/events/batch
https://openapi.linkfarm.ai/v1/events/batchsk_

한 번에 최대 500건.

최대 500건. 야간 대사에 씁니다 — 어제 주문을 통째로 다시 보내면 됩니다. 이미 반영된 주문은 그대로 두고 누락분만 채워집니다.

요청
POST https://openapi.linkfarm.ai/v1/events/batch

{
  "events": [
    { "type": "order.paid",
      "data": { "order_id": "20260801-000123", "amount": 59000,
                "coupon_code": "SUJIN10" } },
    { "type": "order.paid",
      "data": { "order_id": "20260801-000124", "amount": 32000,
                "click_ref": "b_2pQ9zT" } }
  ]
}
응답 · 200 OK
[
  { "id": "evt_7c1f2a9d4b3e8a05c6d1f2", "type": "order.paid",
    "status": "accepted",
    "attribution": { "status": "attributed", "via": "code" },
    "conversion_id": "c6a9373e-…", "livemode": true,
    "request_id": "req_1a2b3c4d5e6f7a8b9c0de0f1" },
  { "id": "evt_b04e1c7d92a5f38601ce4a", "type": "order.paid",
    "status": "accepted",
    "attribution": { "status": "attributed", "via": "click" },
    "conversion_id": "1b77e0aa-…", "livemode": true,
    "request_id": "req_1a2b3c4d5e6f7a8b9c0de0f1" }
]

부분 실패 — 개별 이벤트가 실패하면 에러의 param 에 몇 번째 이벤트인지가 함께 옵니다(예: events[137].data.amount). 해당 건만 고쳐 다시 보내면 됩니다 — 멱등이라 성공한 건을 다시 보내도 중복 집계되지 않습니다. 레이트리밋은 요청 1건이 아니라 담긴 이벤트 수만큼 집계되니, 배치로 묶어도 한도는 같습니다.