AIM UP Developer Docs · v1.0

Reseller API — คู่มือเชื่อมต่อ

สั่งเติมเกมผ่านระบบ AIM UP โดยอัตโนมัติ แบบเครดิต prepaid — เติมไม่สำเร็จคืนเครดิตอัตโนมัติ แจ้งผลด้วย webhook ไม่ต้อง polling

ภาพรวม

บัญชี Reseller ผูกกับกระเป๋าเครดิตของคุณบน AIM UP — เติมเครดิตเข้าก่อน ทุกออเดอร์ตัดจากเครดิตทันทีที่สั่ง และถ้าการเติมไม่สำเร็จ ระบบคืนเครดิตให้อัตโนมัติ ไม่ต้องเปิดเคลม

ร้านคุณ ── POST /orders ──▶ AIM UP ──▶ เติมเข้าเกม
        ◀── Webhook แจ้งผล (สำเร็จ/ไม่สำเร็จ + เหตุผล) ──┘

การเชื่อมต่อ

Base URLhttps://aimup.fast/api/reseller/v1
รูปแบบข้อมูลJSON (UTF-8)
ยืนยันตัวตนHeader: Authorization: Bearer <API_KEY>
Rate limit60 requests / นาที ต่อ key (เกิน → HTTP 429)
IP whitelistไม่บังคับแต่แนะนำ — แจ้ง IP เซิร์ฟเวอร์ของคุณตอนเปิดบัญชี ระบบจะรับเฉพาะจาก IP นั้น (key หลุดก็ใช้จากที่อื่นไม่ได้)
เก็บ API key เป็นความลับ — ใส่ environment variable เท่านั้น ห้าม hardcode ในโค้ดหรือวางในแชท ถ้าหลุดแจ้ง AIM UP เพื่อออก key ใหม่ได้ทันที (key เดิมถูกยกเลิก)

ดูรายการสินค้า

GET /products
{
  "products": [
    {
      "sku": "7665303b-a4c2-4376-82a5-22fedcdc29ff",
      "game": "Garena Free Fire",
      "name": "33 เพชร",
      "mode": "normal",
      "is_preorder": false,
      "delivery_eta": null,
      "price": 8.50,
      "cashback_pct": 0.2,
      "currency": "THB",
      "fields": [
        { "key": "player_id", "label": "UID", "required": true }
      ],
      "active": true
    },
    {
      "sku": "3a556718-cf54-47c7-8db0-605674d367ed",
      "game": "VALORANT(PRE-ORDER)",
      "name": "475 VP",
      "mode": "preorder",
      "is_preorder": true,
      "delivery_eta": "1–3 วัน",
      "price": 130.00,
      "cashback_pct": 9,
      "currency": "THB",
      "fields": [
        { "key": "player_id", "label": "Riot ID", "required": true }
      ],
      "active": true
    }
  ]
}
  • price = ราคาตั้ง (Base) ที่ตัดเครดิตจริง — คงที่ ไม่ผูกกับโปรหน้าร้าน · สิทธิประโยชน์คือ cashback_pct: เงินคืน x% ของราคา Base เข้าเครดิตทันทีที่ออเดอร์สำเร็จ ตามเรท ณ ตอนสั่งซื้อ — เรทปรับตามรอบสินค้า (ช่วงจำนวนจำกัด = เรทพิเศษ) และ เงื่อนไขของแต่ละบัญชี — ยึดค่าที่ endpoint นี้ตอบเสมอ (0 = ไม่มีเงินคืน)
  • game = ชื่อสินค้าเต็ม — วิธีเติม/ภูมิภาคอยู่ใน วงเล็บท้ายชื่อ เช่น VALORANT(PRE-ORDER), VALORANT(MIDNIGHT) ชื่อแพ็กระหว่างสินค้าซ้ำกันได้เป๊ะ ("475 VP" มีทั้งปกติ/พรีออเดอร์ — คนละ sku คนละราคา คนละเรท) — ให้ยึด sku เป็นตัวแยกเสมอ ห้ามจับคู่ด้วยชื่อ · mode = normal หรือ preorder · delivery_eta = ระยะเวลาที่ของจะเข้า (เฉพาะพรีออเดอร์) · เรทเงินคืนของพรีออเดอร์คิดแบบเดียว กับแพ็คปกติ (จ่าย Base แล้วรับเงินคืนตาม cashback_pct ของแพ็คนั้น สำเร็จแล้วเข้าเครดิต) เช็คค่าจริงจาก endpoint นี้ก่อนสั่งเสมอ แลกกับได้ของช้ากว่าแพ็คปกติ
  • fields = ข้อมูลที่ต้องส่งตอนสั่ง แต่ละเกมไม่เหมือนกัน (บางเกมมี server เพิ่ม) — ส่งเฉพาะที่ required: true ก็พอ
  • สินค้าที่ไม่อยู่ในรายการ = ไม่เปิดขายส่ง สั่งแล้วได้ 404

สร้างออเดอร์

POST /orders
{
  "idempotency_key": "shop123-order-98765",
  "sku": "7665303b-a4c2-4376-82a5-22fedcdc29ff",
  "fields": { "player_id": "123456789" }
}

ตอบกลับ (HTTP 201):

{
  "order_id": "f8c12152-a435-4e1a-b4c1-655d5c6b68c9",
  "code": "RSL2607XXXXXX",
  "status": "processing",
  "sku": "7665303b-a4c2-4376-82a5-22fedcdc29ff",
  "mode": "normal",
  "is_preorder": false,
  "eta_at": null,
  "price": 8.50,
  "cashback_pct": 0.2,
  "balance_after": 991.50,
  "created_at": "2026-07-18T10:00:00+07:00"
}
สั่งพรีออเดอร์: ใช้ sku ของแพ็กที่ is_preorder: true — ไม่ต้องส่ง พารามิเตอร์เพิ่มใดๆ ระบบผูกโหมดจาก sku ให้เอง · ผลลัพธ์จะได้ "status": "preorder" พร้อม eta_at = เวลาที่คาดว่าของจะเข้า
Idempotency (สำคัญมาก): idempotency_key = รหัสอ้างอิงฝั่งคุณ ห้ามซ้ำต่อออเดอร์ — ถ้ายิงซ้ำด้วย key เดิม (เช่น network timeout แล้ว retry) ระบบคืนออเดอร์ใบเดิม (HTTP 409) ไม่สร้างใหม่ ไม่ตัดเงินซ้ำ — retry ได้ปลอดภัยเสมอ

เช็คสถานะออเดอร์

GET /orders/{order_id}
{
  "order_id": "f8c12152-a435-4e1a-b4c1-655d5c6b68c9",
  "code": "RSL2607XXXXXX",
  "status": "completed",
  "mode": "normal",
  "is_preorder": false,
  "eta_at": null,
  "reason": null,
  "refunded": false,
  "created_at": "2026-07-18T10:00:00+07:00",
  "completed_at": "2026-07-18T10:03:12+07:00"
}

ใช้เมื่อไหร่ก็ได้ — แต่ช่องทางหลักในการรับผลคือ Webhook (เร็วกว่าและไม่เปลือง rate limit)

เช็คเครดิตคงเหลือ

GET /balance
{ "balance": 991.50, "currency": "THB" }

สถานะออเดอร์

processing ──▶ completed                     (จบ ✓)
     └───────▶ failed (คืนเครดิตอัตโนมัติ)    (จบ ✗)
processingรับออเดอร์แล้ว กำลังเติม (ปกติ 1-5 นาที)
completedเติมสำเร็จ — เงินคืน (ถ้ามี) เข้าเครดิตอัตโนมัติ
failedไม่สำเร็จ — ดูสาเหตุใน reason, เครดิตคืนเข้าบัญชีแล้ว (refunded: true)
พรีออเดอร์: ตอนสร้างออเดอร์จะได้ "status": "preorder" แต่ตอน GET /orders/{id} และใน Webhook จะรายงานเป็น processing จนกว่าจะเติมเสร็จ (เพื่อให้ระบบเดิม ทำงานต่อได้โดยไม่ต้องแก้) — ดูว่าเป็นพรีออเดอร์หรือไม่จาก is_preorder และเวลาที่ของจะเข้าจาก eta_at

ค่า reason ที่เป็นไปได้ (ส่งต่อให้ลูกค้าปลายทางของคุณได้เลย):

  • กรุณาตรวจสอบ ID ใหม่อีกครั้ง
  • กรุณาตรวจสอบภูมิภาคในเกมอีกครั้ง
  • บัญชีของคุณถูกระงับการใช้งานไม่สามารถทำรายการได้
  • ไม่สามารถซื้อสินค้านี้ได้
  • ราคาสินค้าไม่ถูกต้อง
  • ไม่สามารถทำรายการได้

Webhook แจ้งผล

ตั้ง Callback URL ตอนเปิดบัญชี (แก้ทีหลังได้) — ทุกครั้งที่ออเดอร์จบ AIM UP จะ POST ไปหาคุณ:

{
  "event": "order.completed",
  "order_id": "f8c12152-a435-4e1a-b4c1-655d5c6b68c9",
  "code": "RSL2607XXXXXX",
  "idempotency_key": "shop123-order-98765",
  "status": "completed",
  "reason": null,
  "refunded": false,
  "sent_at": "2026-07-18T10:03:12+07:00"
}

แยก event ด้วยฟิลด์ event เสมอ — อนาคตอาจมี event ใหม่เพิ่ม ผู้รับควรข้าม event ที่ไม่รู้จักแทนที่จะ error

การตรวจลายเซ็น (ต้องทำ): ทุก webhook มี header X-AimUp-Signature = HMAC-SHA256 ของ raw body ด้วย Webhook Secret ของคุณ

import hmac, hashlib, os

def verify(raw_body: bytes, signature: str) -> bool:
    secret = os.environ["AIMUP_WEBHOOK_SECRET"].encode()
    expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)
  • คำนวณจาก raw body ตรงๆ — ห้าม parse JSON แล้ว serialize ใหม่ (ลำดับ key เปลี่ยน = ลายเซ็นไม่ตรง)
  • ตอบ 200 ภายใน 10 วินาที = รับทราบ · ไม่ตอบ/ตอบอย่างอื่น → ส่งซ้ำอีก 3 ครั้ง (1, 5, 15 นาที)
  • ฝั่งคุณต้องรับซ้ำได้โดยไม่ประมวลผลสองรอบ (เช็คจาก order_id)
  • เซิร์ฟเวอร์คุณล่มไม่เป็นไร — ใช้ GET /orders/{id} ตามเก็บย้อนหลังได้เสมอ

Error codes

HTTPcodeความหมาย / วิธีจัดการ
401unauthorizedAPI key ผิด / ถูกเพิกถอน
402insufficient_creditเครดิตไม่พอ — เติมเครดิตก่อนแล้วสั่งใหม่
404sku_not_foundไม่มีสินค้านี้ / ไม่เปิดขายส่ง
409duplicateidempotency_key ซ้ำ → body คือออเดอร์ใบเดิม (ไม่ใช่ error จริง)
422invalid_fieldsข้อมูล fields ไม่ครบ/ผิดรูปแบบ — ดูรายละเอียดใน message
429rate_limitedยิงถี่เกิน 60 ครั้ง/นาที — หน่วงแล้วค่อยยิงใหม่
503temporarily_unavailableระบบปิดปรับปรุงชั่วคราว — retry ภายหลัง

เริ่มใช้งาน

  1. สมัครสมาชิก aimup.fast แล้วติดต่อ AIM UP ขอเปิดบัญชี Reseller (แจ้งชื่อร้าน + Callback URL)
  2. เปิดใช้ 2FA ในบัญชีของคุณ แล้วไปที่ aimup.fast/me/reseller เพื่อออก API key + Webhook Secret ด้วยตัวเอง — แสดงครั้งเดียว เห็นเฉพาะคุณ (ทีมงานไม่เห็น) รีเซ็ตเองได้ตลอด
  3. ทดสอบให้ครบ: สั่งสำเร็จ · สั่ง fail · รับ webhook · ตรวจลายเซ็น · retry ด้วย idempotency_key เดิม
  4. เติมเครดิต → เริ่มใช้งานจริง

ตัวอย่างครบวงจร:

# 1. ดูสินค้า
curl -H "Authorization: Bearer $KEY" \
  https://aimup.fast/api/reseller/v1/products

# 2. สั่งเติม
curl -X POST https://aimup.fast/api/reseller/v1/orders \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"idempotency_key":"myshop-1001","sku":"<sku>","fields":{"player_id":"123456789"}}'

# 3. รอ webhook หรือเช็คเอง
curl -H "Authorization: Bearer $KEY" \
  https://aimup.fast/api/reseller/v1/orders/<order_id>
AIM UP · บริษัท เอม อัพ เพย์เมนท์ จำกัด · เอกสาร v1.0 — สเปกอาจปรับปรุงโดยจะแจ้งคู่ค้าทุกครั้ง