{
  "openapi": "3.1.0",
  "info": {
    "title": "Payment Order Center Customer API",
    "version": "1.3.0",
    "description": "One customer API for two channels. UPI supports mode=EXTRACT|READY_LINK; Korea KK currently accepts mode=READY_LINK with a customer-supplied NicePay payment_url. Korea KK validates only the NicePay URL format and does not inspect the payment amount. Legacy productType requests remain supported; when both forms are supplied, they must describe the same product."
  },
  "servers": [
    {
      "url": "https://customer.i7wap.xyz"
    }
  ],
  "components": {
    "securitySchemes": {
      "CdkKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CDK-Key"
      },
      "CustomerOrderToken": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "CustomerOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "orderNo": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "UPI",
              "KAKAO_KK"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "EXTRACT",
              "READY_LINK"
            ]
          },
          "productType": {
            "type": "string",
            "enum": [
              "ACCOUNT_EXTRACT",
              "READY_LINK",
              "KAKAO_EXTRACT",
              "KAKAO_AT"
            ]
          },
          "status": {
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Account email when the upstream returns one"
          },
          "cdk": {
            "type": [
              "object",
              "null"
            ],
            "description": "CDK usage snapshot returned on order creation, polling, and CDK order listing.",
            "properties": {
              "totalCount": {
                "type": "integer",
                "description": "Total uses assigned to this CDK."
              },
              "usedCount": {
                "type": "integer",
                "description": "Uses permanently consumed by successful orders."
              },
              "frozenCount": {
                "type": "integer",
                "description": "Uses temporarily held by pending orders."
              },
              "availableCount": {
                "type": "integer",
                "description": "Uses currently available: totalCount - usedCount - frozenCount."
              }
            }
          },
          "qualification": {
            "type": "object"
          },
          "upi": {
            "type": "object"
          },
          "extraction": {
            "type": "object"
          },
          "payment": {
            "type": "object"
          },
          "subscription": {
            "type": "object"
          },
          "problemReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/customer/orders": {
      "get": {
        "summary": "List orders for a CDK",
        "description": "Every returned order includes a cdk snapshot with totalCount, usedCount, frozenCount, and availableCount. Use cdk.availableCount for the current remaining uses.",
        "security": [
          {
            "CdkKey": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order list"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "State conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Temporary upstream or network failure",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Submit a channel order",
        "description": "Prefer channel and mode. UPI supports ACCOUNT_EXTRACT=UPI/EXTRACT and READY_LINK=UPI/READY_LINK. Korea KK currently supports KAKAO_AT=KAKAO_KK/READY_LINK and only requires the customer-supplied NicePay payment_url; Session Cookie, Session Token, and AT are not required. The Korea link check validates only the HTTPS NicePay checkout path and does not inspect the payment amount. Rejections return a precise error.code and error.details.failures array.",
        "security": [
          {
            "CdkKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "title": "UPI · Platform extraction",
                    "type": "object",
                    "required": [
                      "session_cookie"
                    ],
                    "anyOf": [
                      {
                        "required": [
                          "channel",
                          "mode"
                        ]
                      },
                      {
                        "required": [
                          "productType"
                        ]
                      }
                    ],
                    "dependentRequired": {
                      "channel": [
                        "mode"
                      ],
                      "mode": [
                        "channel"
                      ]
                    },
                    "properties": {
                      "channel": {
                        "const": "UPI",
                        "description": "Recommended explicit channel"
                      },
                      "mode": {
                        "const": "EXTRACT",
                        "description": "Recommended explicit mode"
                      },
                      "productType": {
                        "const": "ACCOUNT_EXTRACT",
                        "description": "Legacy-compatible alias for channel=UPI and mode=EXTRACT"
                      },
                      "credential": {
                        "type": "string",
                        "description": "ChatGPT session token, Cookie, or Session JSON"
                      }
                    }
                  },
                  {
                    "title": "UPI · Ready payment link",
                    "type": "object",
                    "required": [
                      "credential",
                      "payment_url"
                    ],
                    "anyOf": [
                      {
                        "required": [
                          "channel",
                          "mode"
                        ]
                      },
                      {
                        "required": [
                          "productType"
                        ]
                      }
                    ],
                    "dependentRequired": {
                      "channel": [
                        "mode"
                      ],
                      "mode": [
                        "channel"
                      ]
                    },
                    "properties": {
                      "channel": {
                        "const": "UPI",
                        "description": "Recommended explicit channel"
                      },
                      "mode": {
                        "const": "READY_LINK",
                        "description": "Recommended explicit mode"
                      },
                      "productType": {
                        "const": "READY_LINK",
                        "description": "Legacy-compatible alias for channel=UPI and mode=READY_LINK"
                      },
                      "credential": {
                        "type": "string",
                        "description": "Credential belonging to the submitted payment link"
                      },
                      "payment_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Supported hosted UPI payment link"
                      }
                    }
                  },
                  {
                    "title": "Korea KK · Ready NicePay link",
                    "type": "object",
                    "required": [
                      "payment_url"
                    ],
                    "anyOf": [
                      {
                        "required": [
                          "channel",
                          "mode"
                        ]
                      },
                      {
                        "required": [
                          "productType"
                        ]
                      }
                    ],
                    "dependentRequired": {
                      "channel": [
                        "mode"
                      ],
                      "mode": [
                        "channel"
                      ]
                    },
                    "properties": {
                      "channel": {
                        "const": "KAKAO_KK",
                        "description": "Recommended explicit channel"
                      },
                      "mode": {
                        "const": "READY_LINK",
                        "description": "Recommended explicit mode"
                      },
                      "productType": {
                        "const": "KAKAO_AT",
                        "description": "Legacy-compatible alias for channel=KAKAO_KK and mode=READY_LINK"
                      },
                      "payment_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Complete NicePay checkout link"
                      }
                    }
                  }
                ]
              },
              "examples": {
                "upiExtract": {
                  "summary": "UPI · Platform extraction",
                  "value": {
                    "channel": "UPI",
                    "mode": "EXTRACT",
                    "credential": "SESSION_TOKEN_REDACTED"
                  }
                },
                "upiReadyLink": {
                  "summary": "UPI · Ready payment link",
                  "value": {
                    "channel": "UPI",
                    "mode": "READY_LINK",
                    "credential": "SESSION_TOKEN_REDACTED",
                    "payment_url": "https://payments.stripe.com/upi/instructions/REDACTED"
                  }
                },
                "kakaoReadyLink": {
                  "summary": "Korea KK · Ready NicePay link",
                  "value": {
                    "channel": "KAKAO_KK",
                    "mode": "READY_LINK",
                    "payment_url": "https://pay.nicepay.co.kr/v1/checkout/pay/REDACTED"
                  }
                },
                "legacyProductType": {
                  "summary": "Legacy-compatible productType request",
                  "value": {
                    "productType": "KAKAO_AT",
                    "payment_url": "https://pay.nicepay.co.kr/v1/checkout/pay/REDACTED"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order created. The order object includes the current CDK usage snapshot. Save customerToken and poll pollUrl for qualification, extraction, expiry, and Plus status.",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "data": {
                    "order": {
                      "id": "ORDER_ID",
                      "orderNo": "ORDER-NO",
                      "channel": "KAKAO_KK",
                      "mode": "READY_LINK",
                      "productType": "KAKAO_AT",
                      "status": "PENDING"
                    },
                    "customerToken": "CUSTOMER_ORDER_TOKEN",
                    "pollUrl": "/api/v1/customer/orders/ORDER_ID"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "State conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Explicit submission rejection. Korea ready-link submissions are rejected when the NicePay payment URL is missing or does not match the required checkout format. The Korea KK submission path does not perform an amount check.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                },
                "examples": {
                  "invalidLink": {
                    "summary": "Not a NicePay payment link",
                    "value": {
                      "error": {
                        "code": "invalid_payment_url",
                        "message": "韩国提链服务未返回有效 NicePay 支付长链接。订单未创建，本次未扣 CDK 次数。",
                        "details": {
                          "failures": [
                            {
                              "code": "invalid_payment_url",
                              "message": "仅支持 https://pay.nicepay.co.kr/v1/checkout/pay/.../fpmandate_... 格式",
                              "statusCode": 400
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Temporary upstream or network failure",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/orders/{orderId}": {
      "get": {
        "summary": "Get order status",
        "security": [
          {
            "CustomerOrderToken": []
          },
          {
            "CdkKey": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order status"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "State conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Temporary upstream or network failure",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/orders/{orderId}/cancel": {
      "post": {
        "summary": "Cancel a customer order that is still waiting in the scanner hall",
        "description": "Only a PENDING order that has not been assigned to a scanner can be cancelled. Frozen CDK capacity is released; assigned or checking orders are rejected.",
        "security": [
          {
            "CustomerOrderToken": []
          },
          {
            "CdkKey": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancellation result"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "State conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Temporary upstream or network failure",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/orders/{orderId}/resubmit": {
      "post": {
        "summary": "Resubmit an eligible scanner-timeout or unclaimed hall order (maximum two customer retries)",
        "security": [
          {
            "CustomerOrderToken": []
          },
          {
            "CdkKey": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order returned to the scanner hall"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "State conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Temporary upstream or network failure",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "details": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
