สร้างออเดอร์
/api/v1/ordersorders:writeซื้อสินค้าหนึ่งชิ้นแล้วจ่ายด้วยเงินในกระเป๋าของคุณ · cdkey (คีย์เกม) กับ account1 (บัญชีเกมใหม่ที่ยังไม่เคยใช้) ได้รับสินค้าทันทีในคำขอนี้ · ส่วน account2 (บัญชีมือสอง) จะได้รับสินค้าทีหลังทาง callback หรือด้วยการอ่านออเดอร์ซ้ำ เพราะต้องเข้าไปตรวจสอบบัญชีก่อนซื้อ ซึ่งใช้เวลานานเกินกว่าจะรอจบในคำขอเดียว คำขอนี้จึงแค่รับเรื่องเข้าคิวไว้ · ทุกคำตอบมี order_id ติดมาด้วย เก็บไว้เสมอเพราะเป็นทางเดียวที่จะกลับมาดูออเดอร์นี้ได้ · ถ้าคำขอ timeout หรือคุณไม่แน่ใจว่ามันสำเร็จ ให้ส่งคำขอเดิมซ้ำด้วย request_id เดิม ห้ามเปลี่ยนเป็นค่าใหม่
request_id เดิม = ได้คำตอบเดิม ไม่ใช่ซื้อรอบสอง
ยิงซ้ำด้วย request_id เดิม และเนื้อคำขอเหมือนเดิมทุกฟิลด์ ได้ 200 พร้อมออเดอร์เดิม ไม่มีการสั่งซื้อรอบสอง · ยิงซ้ำด้วย request_id เดิม แต่ type / product_id / item_id / expected_price ต่างจากเดิม ได้ 409 idempotency_conflict และออเดอร์เดิมไม่ถูกแตะเลยสักฟิลด์ · สี่ฟิลด์นั้นคือทั้งหมดที่เราเอามาเทียบว่าเป็นคำขอเดียวกันหรือไม่ ฟิลด์อื่นในเนื้อคำขอไม่มีผล · เมื่อคำตอบหลุดกลางทาง ให้ยิงคำขอเดิมซ้ำแบบไม่แก้อะไรเลย นั่นคือเหตุผลทั้งหมดที่ฟิลด์นี้มีอยู่ — ผลที่เป็นไปได้มีแค่สองอย่างคือได้ออเดอร์เดิมกลับมา หรือออเดอร์เพิ่งถูกสร้างเป็นครั้งแรก · การเปลี่ยน request_id เพื่อลองใหม่คือการสั่งซื้อครั้งที่สอง ซึ่งหมายถึงจ่ายเงินสองรอบเมื่อครั้งแรกสำเร็จไปแล้วจริง
คำถามว่าจ่ายไปแล้วเท่าไหร่ มีคำตอบอยู่ที่ charged ที่เดียว
รหัสข้อผิดพลาดตัวเดียวกันมาถึงคุณได้จากหลายจังหวะ และแต่ละจังหวะเงินเดินไปไม่เท่ากัน ส่วน HTTP status ก็ไม่ได้บอกเรื่องนี้เลย — price_changed ที่ตอบสด ๆ ตอนสั่งเกิดขึ้นก่อนแตะเงิน แต่รหัสเดียวกันบนออเดอร์ account2 ที่จบเป็น failed เกิดหลังจากที่เงินถูกกันไว้แล้ว ส่วน supplier_failed ของไอดีมือสองมักเกิดตั้งแต่ตอนตรวจสอบบัญชี ซึ่งอยู่ก่อนขั้นตัดเงินทั้งหมด · อย่าเดาจากรหัสหรือจากสถานะ ให้กระทบยอดจาก charged ของออเดอร์นั้นอย่างเดียว — ค่านี้เป็น null เมื่อออเดอร์ยังไม่มีบันทึกการหักเงิน และเป็นอ็อบเจกต์เมื่อมีแล้ว
queued ไม่ได้รับประกันเวลา และตัวเลขข้างล่างเป็นของทั้งระบบรวมกัน
เราซื้อไอดีมือสองให้ ทีละหนึ่งออเดอร์ เรียงตามลำดับที่เข้ามา และเป็นคิวเดียวที่ทุก reseller ใช้ร่วมกัน ไม่ได้ซื้อพร้อมกันหลายออเดอร์ · ปกติออเดอร์หนึ่งจะรู้ผลในเวลาราวสองนาที เพราะการตรวจสอบบัญชี ครั้งแรก ของแต่ละออเดอร์กินเวลานานกว่าที่หนึ่งรอบทำงานจะทำจบได้ · เพดานที่เกิดขึ้นจริงคือราว 24 ออเดอร์ต่อชั่วโมงของทั้งระบบรวมกัน ไม่ใช่ต่อ reseller หนึ่งราย และไม่ใช่ตัวเลขกรณีดีที่สุด · คิวไม่มีช่องแยกให้รายใครและไม่มีเพดานความยาว การยิง account2 เข้ามาพร้อมกันทีละมาก ๆ ทำให้ออเดอร์ของทุกคนรวมทั้งของคุณเองช้าลง · ออเดอร์ที่ตรวจหรือซื้อไม่สำเร็จจะถูกลองใหม่ให้โดยเว้นช่วงห่างขึ้นเรื่อย ๆ สูงสุด 5 ครั้ง แล้วจึงจบเป็น failed · นับเป็นครั้งเฉพาะตอนที่เราลงมือทำกับออเดอร์นั้นจริง ตอนที่ออเดอร์ยังไม่ถึงคิวไม่นับ ดังนั้นเลข 5 ครั้งนี้ไม่ใช่ตัวบอกว่าออเดอร์หนึ่งจะรออยู่ในคิวได้นานแค่ไหน
การปฏิเสธที่ด่านยืนยันตัวตนเกิดกับเอนด์พอยต์นี้ด้วย
ห้ารหัสของด่านยืนยันตัวตน — invalid_key (401) · key_revoked (401) · insufficient_scope (403) · quota_exceeded (429) · too_many_inflight (429) — เกิดได้กับทุกเอนด์พอยต์ รวมทั้งเอนด์พอยต์นี้ เพราะถูกโยนตั้งแต่ก่อนคำขอจะเดินไปถึงตรรกะของหน้านี้เลยสักบรรทัด (scope ที่ต้องมีคือค่าที่ประกาศไว้หัวหน้านี้) · แท็บคำตอบด้านบนจึงไล่เฉพาะสิ่งที่เอนด์พอยต์นี้เองตอบ ไม่ได้แปลว่าห้ารหัสนั้นเกิดที่นี่ไม่ได้ · รายละเอียดครบทุกตัวอยู่ที่ หน้าเอนด์พอยต์ตัวตนที่ /developers/access/me ที่เดียว ทั้ง HTTP status ของแต่ละตัว · ตัวไหนกินโควตารายวันบ้าง · header อะไรกลับมาบ้าง · และทำไม 429 สองตัวต้องรับมือคนละแบบ — จงใจไม่คัดลอกมาไว้ทุกหน้า เพราะสำเนาที่สองคือที่ที่ลืมแก้ตามในวันที่กติกาเปลี่ยน
ข้อมูลที่ต้องส่ง
Request body
| ชื่อ | ชนิด | วิธีใช้ |
|---|---|---|
| typeบังคับ | cdkey · account1 · account2 | ประเภทสินค้าที่กำลังจะซื้อ และเป็นฟิลด์เดียวที่ตัดสินว่าคุณจะได้ของเมื่อไหร่ รายละเอียดและข้อควรระวัง
|
| product_idบังคับ | สตริง ยาวไม่เกิน 200 ตัวอักษร ใช้ได้เฉพาะ A-Z a-z 0-9 _ - | รหัสสินค้าที่ได้จากแคตตาล็อก คือค่าในฟิลด์ id ของสินค้าชิ้นนั้น · รูปที่ผิดกฎถูกปฏิเสธด้วย bad_request ตั้งแต่ก่อนแตะฐานข้อมูล |
| item_idไม่บังคับ | รูปแบบเดียวกับ product_id | บังคับเฉพาะ account2 และไม่ใช้กับประเภทอื่นเลย คือบัญชีมือสองหนึ่งชิ้นที่คุณเลือกมาจาก GET /api/v1/products/{product_id}/itemsรายละเอียดและข้อควรระวัง
|
| expected_priceบังคับ | ตัวเลข หรือสตริงตัวเลข (ไม่เกิน 40 ตัวอักษร) | ราคา หน่วยบาท ที่คุณยอมจ่าย คัดลอกมาจากคำตอบของแคตตาล็อกสำหรับสินค้าหรือบัญชีชิ้นเดียวกันนี้ เซิร์ฟเวอร์คิดราคาใหม่เองทุกครั้งแล้วเทียบกับค่านี้แบบตรงตัว ไม่ตรงเมื่อไหร่ก็ปฏิเสธด้วย price_changed แทนที่จะคิดเงินคุณที่ราคาอื่นรายละเอียดและข้อควรระวัง
|
| request_idบังคับ | สตริง ยาวไม่เกิน 200 ตัวอักษร | กุญแจกันสั่งซ้ำที่คุณเป็นคนตั้งเอง ใช้ค่าที่ไม่ซ้ำต่อหนึ่งคำสั่งซื้อจริง (เช่น UUID) แล้วเก็บไว้ฝั่งคุณ ส่งค่าเดิมซ้ำแล้วจะได้ออเดอร์เดิมที่มีอยู่แล้วกลับมา ไม่ใช่การซื้อรอบสอง รายละเอียดและข้อควรระวัง
|
Header
| ชื่อ | ชนิด | วิธีใช้ |
|---|---|---|
| Authorizationบังคับ | string | คีย์ของคุณในรูป Bearer <คีย์> ต้องส่งมาทุกคำขอ · คีย์ที่มีแต่ orders:write สั่งซื้อได้แต่ตามผลไม่ได้ ให้ขอ orders:read มาด้วยเสมอ |
| Content-Typeบังคับ | string | ต้องเป็น application/json เพราะ body ที่ประกาศเป็นชนิดอื่นจะถูกอ่านเป็นข้อความล้วนหรือเป็นฟอร์ม แล้วตกเป็น 400 bad_request ทั้งที่ตัว JSON เขียนถูกทุกตัวอักษรรายละเอียดและข้อควรระวัง
|
ข้อมูลที่ได้รับ
| ชื่อ | ชนิด | วิธีใช้ |
|---|---|---|
| order_id | สตริง หรือ null | รหัสออเดอร์ ขึ้นต้นด้วย ord_ ตามด้วยเลขฐานสิบหก 24 ตัวรายละเอียดและข้อควรระวัง
|
| status | สตริง หรือ null | สถานะของออเดอร์ตอนนี้ รายละเอียดและข้อควรระวัง
|
| type | สตริง หรือ null | ประเภทที่สั่งไว้ — เป็นตัวบอกว่า delivery จะมารูปไหน |
| product_id | สตริง หรือ null | รหัสสินค้าที่สั่ง |
| price | ตัวเลข หรือ null | ราคาที่ตกลงกันไว้ หน่วยบาท เท่ากับ expected_price ที่ส่งมา |
| charged | อ็อบเจกต์ หรือ null | { amount, currency } คือยอดที่หักจากกระเป๋าจริง และเป็นคำตอบ เดียว ของคำถามว่าออเดอร์นี้จ่ายไปแล้วหรือยังรายละเอียดและข้อควรระวัง
|
| delivery | อ็อบเจกต์ หรือ null | ตัวสินค้าที่ส่งมอบ มีค่าเฉพาะตอน status เป็น completed และมาได้ สองรูปที่ไม่มีฟิลด์ร่วมกันเลยสักตัว คือ cdkey กับ account1 ได้ { keys: [{ serial }] } ส่วน account2 ได้ login, password, email, email_password และ extraรายละเอียดและข้อควรระวัง
|
| error | อ็อบเจกต์ หรือ null | สาเหตุที่ไม่สำเร็จ มีค่าเฉพาะตอน status เป็น failed โดยมี { code, message } อยู่ข้างในรายละเอียดและข้อควรระวัง
|
| created_at | สตริง ISO 8601 (UTC) หรือ null | เวลาที่ออเดอร์ถูกสร้าง |
| updated_at | สตริง ISO 8601 (UTC) หรือ null | เวลาที่ออเดอร์ถูกแก้ครั้งล่าสุด |
สถานะที่อาจได้รับ
| สถานะ | รหัส | ความหมาย |
|---|---|---|
| 200 | — | ยิงซ้ำ — ได้ออเดอร์เดิมกลับไป ไม่ได้ซื้อใหม่ คุณส่งคำขอเดิมซ้ำทุกฟิลด์ (เช่นตอนคำตอบครั้งแรกหลุดกลางทาง) จึงได้ออเดอร์เดิมกลับไปตามสถานะล่าสุดของมัน ซึ่งในตัวอย่างนี้คือออเดอร์ account2 ที่เราซื้อสำเร็จไปแล้วระหว่างนั้นรายละเอียดและข้อควรระวัง
|
| 201 | — | ซื้อจบในคำขอนี้ — รู้ผลแล้ว ไม่ต้องรออะไรต่อ สั่งซื้อเสร็จสิ้นแล้วตั้งแต่ในคำขอนี้ คุณจึงอ่านผลได้จากคำตอบนี้เลย ไม่ต้องรอ callback และไม่ต้องเรียกอ่านออเดอร์ซ้ำ รายละเอียดและข้อควรระวัง
|
| 202 | — | หักเงินแล้ว แต่ของยังมาไม่ถึง — ให้อ่านออเดอร์ซ้ำ ออเดอร์นี้มี charged แล้วแต่ delivery ยังเป็น null แปลว่าเราตัดเงินและสั่งของไปแล้ว แต่คีย์ยังส่งมาไม่ทันในคำขอนี้ ซึ่ง เป็นเรื่องปกติ ไม่ใช่ความผิดพลาดรายละเอียดและข้อควรระวัง
|
| 202 | — | กระเป๋าที่ไม่ใช่เงินบาท — price เป็นบาท ส่วน charged เป็นสกุลของกระเป๋าสถานการณ์เดียวกับแถวข้างบน แต่ยกมาให้ดูสำหรับคนที่กระเป๋าไม่ได้ถือเงินบาท รายละเอียดและข้อควรระวัง
|
| 202 | — | เข้าคิวแล้ว — เราจะไปซื้อไอดีมือสองให้ แล้วแจ้งผลทีหลัง account2 ตอบแบบนี้เสมอ พร้อม status เป็น queued เพราะไอดีมือสองต้องถูกตรวจสอบบัญชีก่อนซื้อ (ล็อกอินเข้าไปดูว่าบัญชียังใช้ได้จริงไหม) ซึ่งใช้เวลานานเกินกว่าจะรอจบในคำขอเดียวรายละเอียดและข้อควรระวัง
|
| 400 | bad_request | เนื้อคำขอไม่ผ่านการตรวจ แก้คำขอแล้วส่งใหม่ด้วย request_id เดิมได้เลยรายละเอียดและข้อควรระวัง
|
| 409 | idempotency_conflict | ใช้ request_id เดิมกับคำขอที่ต่างออกไปคุณใช้ request_id ค่าเดิมกับคำขอที่มีเนื้อหาต่างจากครั้งแรกรายละเอียดและข้อควรระวัง
|
| 404 | product_not_found | ไม่มีสินค้ารหัสนั้น หรือปิดขายแล้ว ขอแคตตาล็อกใหม่แล้วเลือกสินค้าชิ้นอื่น · สินค้าที่ปิดขายกับสินค้าที่ไม่เคยมีตอบเหมือนกันหมดโดยเจตนา · รหัสนี้ไปโผล่เป็น error.code ของออเดอร์ที่จบเป็น failed ได้ด้วย |
| 404 | item_not_found | รายการ account2 ที่เลือกไม่อยู่ในตลาดแล้วบัญชีชิ้นที่คุณเลือกถูกคนอื่นซื้อไปแล้วหรือถูกถอดออกจากตลาดแล้ว ให้ดึงรายการบัญชีรายชิ้นใหม่แล้วเลือกชิ้นอื่น รายละเอียดและข้อควรระวัง
|
| 409 | price_changed | ราคาไม่ตรงกับที่คุณส่งมา ราคาใหม่แนบมาให้ใน data แล้วรายละเอียดและข้อควรระวัง
|
| 409 | out_of_stock | ของหมด หรือถูกคนอื่นซื้อตัดหน้าไป เลือกสินค้าชิ้นอื่น · รหัสนี้ไปโผล่เป็น error.code ของออเดอร์ที่จบเป็น failed ได้ด้วย |
| 409 | price_unavailable | สินค้าชิ้นนั้นคิดราคาให้ไม่ได้ สินค้ามีอยู่จริงแต่ขายผ่าน API ไม่ได้ ให้ข้ามไปก่อนแล้วแจ้งเรา อย่าลบออกจากแคตตาล็อกของคุณ แบบที่ทำกับ product_not_foundรายละเอียดและข้อควรระวัง
|
| 409 | agreed_price_invalid | ราคาที่ส่งมาใช้ไม่ได้ตอนจะคิดเงิน ขอราคาใหม่จากแคตตาล็อกแล้วสั่งใหม่ด้วย request_id ค่าใหม่รายละเอียดและข้อควรระวัง
|
| 404 | wallet_not_found | ไม่พบกระเป๋าเงินของบัญชีนี้ ติดต่อเรา · รหัสนี้ไปโผล่เป็น error.code ของออเดอร์ที่จบเป็น failed ได้ด้วย |
| 400 | insufficient_points | ยอดในกระเป๋าไม่พอสำหรับออเดอร์นี้ เติมเงินแล้วสั่งใหม่ รายละเอียดและข้อควรระวัง
|
| 400 | unsupported_currency | สกุลเงินของกระเป๋าใช้กับรายการนี้ไม่ได้ ติดต่อเรา · รหัสนี้ไปโผล่เป็น error.code ของออเดอร์ที่จบเป็น failed ได้ด้วย |
| 502 | supplier_failed | เราสั่งของกับต้นทางให้ไม่สำเร็จ ตรวจ charged ของออเดอร์ก่อนตัดสินใจสั่งซ้ำเสมอ · รหัสนี้ไปโผล่เป็น error.code ของออเดอร์ที่จบเป็น failed ได้ด้วย และมาถึงคุณได้ทั้งจากจังหวะที่มีเงินขยับและจังหวะที่ไม่มีเลย |
| 500 | order_save_failed | ซื้อของให้แล้วแต่เราบันทึกไม่สำเร็จ — รหัสเดียวที่ห้ามยิงซ้ำ เราหักเงินและสั่งของให้เรียบร้อยแล้ว แต่ขั้นตอนบันทึกผลลงออเดอร์ล้มเหลว รายละเอียดและข้อควรระวัง
|
| 500 | unknown | ปิดด้วยสาเหตุที่เราไม่ได้จัดหมวดไว้ หยุดไว้ก่อนแล้วให้คนดู รายละเอียดและข้อควรระวัง
|