{
  "openapi": "3.1.0",
  "info": {
    "title": "HRUM 흐름 결제 API — 결제·주문·정산·웹훅",
    "version": "2026-11-03",
    "description": "서버에서 X-Partner-Api-Key 로 부른다. 응답은 {success, data}. 각 경로의 x-required-scope 권한이 있는 키(또는 권한을 고르지 않은 전체 권한 키)만 부를 수 있다. 웹훅 서명: Hrum-Signature: t=<unix초>,v1=<hex HMAC-SHA256(secret, `${t}.${raw body}`)>. 안내: https://hrum.ai/hosting-docs.html#payments"
  },
  "servers": [
    {
      "url": "https://api.hrum.ai"
    }
  ],
  "components": {
    "securitySchemes": {
      "partnerKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Partner-Api-Key"
      }
    }
  },
  "paths": {
    "/api/v1/partners/v1/storefront/skus": {
      "post": {
        "summary": "상품 등록",
        "x-required-scope": "payments",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "skuId": "<skuId>",
                    "appId": "<appId>",
                    "name": "사주 리포트",
                    "priceWon": 11000
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "appId": "<appId>",
                "name": "사주 리포트",
                "priceWon": 11000
              }
            }
          }
        }
      }
    },
    "/api/v1/partners/v1/storefront/checkouts": {
      "post": {
        "summary": "결제 열기 (checkoutUrl 로 이용자를 보냄)",
        "x-required-scope": "payments",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "orderId": "sf-a1b2c3",
                    "checkoutUrl": "https://console.hrum.ai/pay.html?orderId=sf-a1b2c3",
                    "expiresAt": "2026-11-03T03:30:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "appId": "<appId>",
                "skuId": "<skuId>",
                "qty": 1,
                "returnUrl": "https://myapp.ridm.ai/paid"
              }
            }
          }
        }
      }
    },
    "/api/v1/partners/v1/storefront/orders/{orderId}": {
      "get": {
        "summary": "주문 확인 (status 가 paid 일 때만 상품 지급)",
        "x-required-scope": "orders.read",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "orderId": "sf-a1b2c3",
                    "status": "paid",
                    "skuId": "<skuId>",
                    "qty": 1,
                    "paidAt": "2026-11-03T03:00:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "description": "환불되면 status 가 partial_canceled / canceled. 환불(refunds) 결과는 이 status 와 웹훅 order.refunded 로 받는다.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "description": "주문번호",
            "schema": {
              "type": "string"
            },
            "example": "sf-a1b2c3"
          }
        ]
      }
    },
    "/api/v1/partners/v1/settlement/sales": {
      "get": {
        "summary": "판매 정산 줄 + 기간 합계",
        "x-required-scope": "settlement.read",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "range": {
                      "from": "2026-11-01",
                      "to": "2026-11-30"
                    },
                    "skuId": null,
                    "payoutStage": "started",
                    "totals": {
                      "orders": 1,
                      "paidWon": 11000,
                      "salesCommissionWon": 1210,
                      "perOrderFeeWon": 110,
                      "pgFeeWon": 363,
                      "sellerWon": 9427,
                      "refundedWon": 0,
                      "amountStatus": "estimated"
                    },
                    "items": [
                      {
                        "orderId": "sf-a1b2c3",
                        "skuName": "사주 리포트",
                        "qty": 1,
                        "status": "paid",
                        "paidAt": "2026-11-03T03:00:00.000Z",
                        "paidWon": 11000,
                        "salesCommissionWon": 1210,
                        "perOrderFeeWon": 110,
                        "pgFeeWon": 363,
                        "sellerWon": 9427,
                        "refundedWon": 0,
                        "amountStatus": "estimated",
                        "pgFeeStatus": "estimated",
                        "pgFeeDiffWon": null
                      }
                    ],
                    "nextCursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "description": "금액은 원. salesCommissionWon·pgFeeWon 은 부가세 포함, 모두 환불을 뺀 값. totals 는 페이지가 아니라 기간 전체 합(콘솔 정산 화면과 같음).",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "시작 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 1일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "끝 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 말일, 최대 366일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "skuId",
            "in": "query",
            "required": false,
            "description": "상품 하나만 (uuid)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1~100, 기본 50",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "이전 응답의 nextCursor (orderId)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/partners/v1/settlement/payouts": {
      "get": {
        "summary": "지급 (예정·완료·미지급) + 기간 합계",
        "x-required-scope": "settlement.read",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "range": {
                      "from": "2026-11-01",
                      "to": "2026-11-30"
                    },
                    "totals": {
                      "scheduled": {
                        "payouts": 0,
                        "grossWon": 0,
                        "feeWon": 0,
                        "feeVatWon": 0,
                        "withholdingWon": 0,
                        "amountWon": 0
                      },
                      "completed": {
                        "payouts": 1,
                        "grossWon": 50000,
                        "feeWon": 100,
                        "feeVatWon": 10,
                        "withholdingWon": 1650,
                        "amountWon": 48240
                      }
                    },
                    "items": [
                      {
                        "id": "po_x1",
                        "payoutDate": "2026-11-04",
                        "amountWon": 48240,
                        "grossWon": 50000,
                        "feeWon": 100,
                        "feeVatWon": 10,
                        "withholdingWon": 1650,
                        "state": "completed",
                        "tossStatus": "COMPLETED",
                        "completedAt": "2026-11-04T02:10:00.000Z"
                      }
                    ],
                    "nextCursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "description": "grossWon = amountWon + feeWon + feeVatWon + withholdingWon. withholdingWon = 개인 판매자 원천징수 3.3% (사업자 0). 기간은 지급일(payoutDate) 기준.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "시작 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 1일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "끝 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 말일, 최대 366일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "scheduled | completed | unpaid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1~100, 기본 20",
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "이전 응답의 nextCursor (지급 id)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/partners/v1/settlement/summary": {
      "get": {
        "summary": "기간 합계 한 번에",
        "x-required-scope": "settlement.read",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "range": {
                      "from": "2026-11-01",
                      "to": "2026-11-30"
                    },
                    "skuId": null,
                    "sales": {
                      "orders": 1,
                      "paidWon": 11000,
                      "salesCommissionWon": 1210,
                      "perOrderFeeWon": 110,
                      "pgFeeWon": 363,
                      "sellerWon": 9427,
                      "refundedWon": 0,
                      "amountStatus": "estimated"
                    },
                    "payouts": {
                      "scheduled": {
                        "payouts": 0,
                        "grossWon": 0,
                        "feeWon": 0,
                        "feeVatWon": 0,
                        "withholdingWon": 0,
                        "amountWon": 0
                      },
                      "completed": {
                        "payouts": 1,
                        "grossWon": 50000,
                        "feeWon": 100,
                        "feeVatWon": 10,
                        "withholdingWon": 1650,
                        "amountWon": 48240
                      }
                    },
                    "payoutFee": {
                      "payoutFeeWon": 100,
                      "payoutFeeVatWon": 10,
                      "label": "지급 신청 1회당 100원(부가세 별도)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "시작 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 1일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "끝 한국 날짜 YYYY-MM-DD (포함, 생략 = 이달 말일, 최대 366일)",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "skuId",
            "in": "query",
            "required": false,
            "description": "판매 합계를 상품 하나로",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/partners/v1/webhooks/endpoint": {
      "get": {
        "summary": "웹훅 주소 조회 (비밀값 없음)",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "endpoint": {
                      "url": "https://myapp.ridm.ai/hrum/webhook",
                      "active": true,
                      "secretHint": "Ab3d",
                      "createdAt": "2026-11-03T03:00:00.000Z",
                      "updatedAt": "2026-11-03T03:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        }
      },
      "put": {
        "summary": "웹훅 주소 등록·변경 (secret 은 새로 만들 때 한 번만)",
        "description": "플랫폼 키로 등록하면 그 플랫폼에서 열린 판매자 주문의 order.paid·order.refunded 사본도 이 주소로 온다(헤더·서명 같음, id 는 판매자 쪽과 다름, data 에 sellerId·spaceId 추가).",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "endpoint": {
                      "url": "https://myapp.ridm.ai/hrum/webhook",
                      "active": true,
                      "secretHint": "Ab3d",
                      "createdAt": "2026-11-03T03:00:00.000Z",
                      "updatedAt": "2026-11-03T03:00:00.000Z"
                    },
                    "secret": "whsec_…"
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "description": "https:// 만, 포트 443·8443. 사설·내부·루프백·링크로컬 주소는 400 WEBHOOK_URL_BLOCKED. secret 은 서버 환경변수에만 둔다.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "url": "https://myapp.ridm.ai/hrum/webhook",
                "rotateSecret": false
              }
            }
          }
        }
      },
      "delete": {
        "summary": "웹훅 끄기",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "active": false
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        }
      }
    },
    "/api/v1/partners/v1/webhooks/test": {
      "post": {
        "summary": "webhook.test 이벤트 보내기",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "202": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "eventId": "evt_0123456789abcdef0123456789abcdef"
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        }
      }
    },
    "/api/v1/partners/v1/webhooks/deliveries": {
      "get": {
        "summary": "웹훅 전송 기록",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "eventId": "evt_0123456789abcdef0123456789abcdef",
                        "type": "order.paid",
                        "status": "delivered",
                        "attempts": 1,
                        "nextAttemptAt": null,
                        "lastStatusCode": 200,
                        "lastError": null,
                        "deliveredAt": "2026-11-03T03:00:05.000Z",
                        "createdAt": "2026-11-03T03:00:00.000Z"
                      }
                    ],
                    "nextCursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "pending | delivered | failed",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1~100, 기본 20",
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "이전 응답의 nextCursor (eventId)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/partners/v1/webhooks/deliveries/{eventId}/redeliver": {
      "post": {
        "summary": "같은 이벤트 다시 보내기",
        "x-required-scope": "webhooks",
        "security": [
          {
            "partnerKey": []
          }
        ],
        "responses": {
          "202": {
            "description": "성공 — 본문은 {success, data}",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "eventId": "evt_0123456789abcdef0123456789abcdef",
                    "status": "pending"
                  }
                }
              }
            }
          },
          "401": {
            "description": "키 없음/무효"
          },
          "403": {
            "description": "KEY_SCOPE_MISSING (키에 이 권한이 없음) 또는 앱 키"
          }
        },
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "이벤트 id",
            "schema": {
              "type": "string"
            },
            "example": "evt_0123456789abcdef0123456789abcdef"
          }
        ]
      }
    }
  },
  "webhooks": {
    "order.paid": {
      "post": {
        "summary": "결제 완료",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "id": "evt_…",
                "type": "order.paid",
                "created": 1762138800,
                "data": {
                  "orderId": "sf-a1b2c3",
                  "appId": "<appId>",
                  "skuId": "<skuId>",
                  "skuName": "사주 리포트",
                  "qty": 1,
                  "totalWon": 11000,
                  "paidAt": "2026-11-03T03:00:00.000Z"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2xx 를 10초 안에"
          }
        }
      }
    },
    "order.refunded": {
      "post": {
        "summary": "환불 한 건",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "id": "evt_…",
                "type": "order.refunded",
                "created": 1762138800,
                "data": {
                  "orderId": "sf-a1b2c3",
                  "refundId": "<uuid>",
                  "amountWon": 11000,
                  "refundedWon": 11000,
                  "status": "canceled",
                  "canceledAt": "2026-11-03T05:00:00.000Z"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2xx"
          }
        }
      }
    },
    "payout.scheduled": {
      "post": {
        "summary": "지급 예정 (잔액 예약)",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "id": "evt_…",
                "type": "payout.scheduled",
                "created": 1762138800,
                "data": {
                  "payoutId": "po_x1",
                  "payoutDate": "2026-11-04",
                  "grossWon": 50000,
                  "feeWon": 100,
                  "feeVatWon": 10,
                  "withholdingWon": 1650,
                  "amountWon": 48240
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2xx"
          }
        }
      }
    },
    "payout.completed": {
      "post": {
        "summary": "지급 완료",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "id": "evt_…",
                "type": "payout.completed",
                "created": 1762138800,
                "data": {
                  "payoutId": "po_x1",
                  "payoutDate": "2026-11-04",
                  "grossWon": 50000,
                  "feeWon": 100,
                  "feeVatWon": 10,
                  "withholdingWon": 1650,
                  "amountWon": 48240,
                  "completedAt": "2026-11-04T02:10:00.000Z"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2xx"
          }
        }
      }
    }
  }
}