เอกสาร API
เริ่มใช้งาน

เอกสาร API

หน้านี้คือสัญญาที่ API ให้ไว้ — สำหรับตอนที่บางอย่างไม่เป็นอย่างที่คิด ส่วนหน้าคีย์คือจุดเริ่มต้นที่มีของให้ก๊อปไปวางได้เลย คำสั่งและชื่อฟิลด์เป็นภาษาอังกฤษเพราะมันมีคำสะกดที่ถูกอยู่แบบเดียว

ไปสร้างคีย์

ทุกจำนวนเป็นเศษหนึ่งส่วนร้อยของดาว

50 หมายถึง 0.50 ดาว · 200 หมายถึง 2.00 · เป็นจำนวนเต็มเสมอ ไม่มีทศนิยม อย่าหารก่อนเทียบสองค่า และอย่าเดาราคา — อ่านจาก /api/catalog ทุกครั้ง

ราคา

อ่านสดจาก /api/catalog ตอนคุณเปิดหน้านี้ ราคาแก้ได้จากคอนโซลตลอดเวลา ตัวเลขที่พิมพ์ค้างไว้จึงยังถูกอยู่นานหลังจากเลิกเป็นความจริงแล้ว

กำลังโหลด

ราคาของการขยายภาพไม่อยู่ในตารางนี้ — มันผูกกับผลงานที่เสร็จแล้วแต่ละชิ้น และกลับมาพร้อมผลงานนั้นใน upscales[] ของ GET /api/projects/<id> หรือจาก tool ชื่อ estimate ถ้าคุณต่อผ่าน MCP

สั่ง แล้วรอ แล้วเอาไฟล์

สามคำสั่งนี้คือทั้งหมด ก๊อปไปวางในเทอร์มินัลได้เลย เปลี่ยนแค่คีย์กับ job id

สั่งทำ

curl -X POST https://gentook.example/api/generate \
  -H "Authorization: Bearer <วางคีย์ของคุณตรงนี้>" \
  -H "Content-Type: application/json" \
  -d '{"model":"image-nano2","prompt":"a red maple leaf on white paper"}'

# 202 {"jobs":[{"id":"cm…","status":"running","error":null}]}
# 502 the SAME shape, with a sentence in each job's "error".

รอให้เสร็จ

# Holds the connection for up to about 50 seconds and answers either way.
# "done": false means carry on — not an error, not a timeout.
curl https://gentook.example/api/jobs/<id>/wait -H "Authorization: Bearer <วางคีย์ของคุณตรงนี้>"

# {"id":"cm…","status":"running","done":false, …}
# {"id":"cm…","status":"completed","done":true,"url":"…","availableUntil":"…"}

# The plain read, if you would rather run your own loop. Every 3 seconds; no faster.
curl https://gentook.example/api/jobs/<id> -H "Authorization: Bearer <วางคีย์ของคุณตรงนี้>"

เอาไฟล์ออกมา

# Follow redirects — and be ready for the body to arrive directly instead,
# which is what happens for a result the provider serves with a credential.
curl -L https://gentook.example/api/jobs/<id>/url \
  -H "Authorization: Bearer <วางคีย์ของคุณตรงนี้>" -o result.jpg

# 410 {"error":"…","code":"windowClosed"}  once it is past availableUntil

ทำไมต้องอ่านซ้ำ

ที่นี่ไม่มีตัววิ่งงานเบื้องหลัง — การอ่านงานคือสิ่งที่ทำให้งานเดิน ยิงแล้วปล่อยทิ้งไว้ งานจะค้างจนหมดอายุ 20 นาทีแล้วถูกยกเลิก ใช้ /wait ดีที่สุดเพราะมันค้างสายรอให้แทน ถ้าอยากเขียนลูปเองให้อ่านทุก 3 วินาที อย่าถี่กว่านั้น · การรอไม่คิดเงิน และงานที่ล้มไม่หักดาว

หกอย่างที่สั่งได้

จำนวนภาพที่แนบคือสิ่งที่บอกว่ากำลังสั่งอะไร · ส่งชื่อโหมดมาใน params.mode และมันต้องตรงกับจำนวนภาพ ไม่ตรงคือถูกปฏิเสธก่อนหักดาว ไม่ใช่รู้ทีหลังตอนได้ของผิด

t2v
0 ภาพ
คลิปจากข้อความล้วน
i2v
1 ภาพ
ภาพนั้นคือเฟรมแรก
interp
2 ภาพ
เฟรมแรกกับเฟรมสุดท้าย คลิปเดินทางระหว่างสองภาพ
r2v
1-3 ภาพ
สิ่งที่อยากให้หน้าตาเป็นแบบนั้น
t2i
0 ภาพ
ภาพจากข้อความล้วน
r2i
1-10 ภาพ
สิ่งที่อยากให้หน้าตาเป็นแบบนั้น

โหมดไม่ได้เปลี่ยนความยาว โมเดลเป็นตัวกำหนด

ทาง MCP ไม่ต้องบอกชื่อโหมด — ส่งภาพมาแล้วบอกว่าเอาไปทำอะไรด้วย use: frames (ภาพคือตำแหน่งในคลิป) หรือ references (ภาพคือสิ่งที่อยากให้หน้าตาเป็นแบบนั้น) ที่เหลือระบบนับให้เอง จึงสั่งชุดที่ไม่มีอยู่จริงไม่ได้เลย

พารามิเตอร์ทุกตัว และค่าที่ได้ถ้าไม่ส่ง

ทุกฟิลด์เป็นตัวเลือก ยกเว้น prompt ฟิลด์ที่ไม่ส่งจะใช้ค่าตั้งต้นของโมเดล ซึ่งแก้ได้จากคอนโซล ตารางข้างล่างจึงอ่านค่าจริงมาแสดง ไม่ได้พิมพ์ทิ้งไว้

จุดที่พลาดกันบ่อยที่สุดคือรูปทรง ถ้าไม่ส่ง aspect จะได้แนวนอนเสมอ ไม่ว่าใน prompt จะเขียนว่าอะไร เพราะ prompt ไม่เคยถูกอ่านเพื่อหาสัดส่วน

วิดีโอ

prompt
ข้อความ
ต้องมี ยกเว้นส่ง jobId แทน
model
สลักจากรายการบน· ค่าตั้งต้น ตัวถูกสุดที่ทำได้
aspect
16:9 | 9:16
ต้องใส่เอง ไม่ใส่คือได้แนวนอน
resolution
720p
มีค่าเดียว ใหญ่กว่านี้คือ upscale ซึ่งคิดเงินอีกรอบ
durationSec
มีความยาวเดียว
use
frames | references· ค่าตั้งต้น references
รูปที่แนบเอาไปทำอะไร
images
ได้ถึง 3 รูป· ค่าตั้งต้น ไม่ส่งก็ได้
promptParts
ข้อความ + imageIndex· ค่าตั้งต้น ไม่ส่งก็ได้
บอกว่าคำไหนหมายถึงรูปไหน
seed
0 … 2147483647· ค่าตั้งต้น ไม่ส่งก็ได้
ไม่ทำให้ได้ผลเดิมซ้ำ
jobId
รหัสงาน· ค่าตั้งต้น ไม่ส่งก็ได้
ใช้รอต่อ ไม่สร้างใหม่ ไม่เสียดาวเพิ่ม

ภาพ

prompt
ข้อความ
ต้องมี ยกเว้นส่ง jobId แทน
model
สลักจากรายการบน· ค่าตั้งต้น ตัวถูกสุดที่ทำได้
aspect
16:9 | 4:3 | 1:1 | 3:4 | 9:16
ต้องใส่เอง ไม่ใส่คือได้ 16:9
resolution
1k
มีค่าเดียว ใหญ่กว่านี้คือ upscale ซึ่งคิดเงินอีกรอบ
images
ได้ถึง 10 รูป· ค่าตั้งต้น ไม่ส่งก็ได้
promptParts
ข้อความ + imageIndex· ค่าตั้งต้น ไม่ส่งก็ได้
บอกว่าคำไหนหมายถึงรูปไหน
seed
0 … 2147483647· ค่าตั้งต้น ไม่ส่งก็ได้
ไม่ทำให้ได้ผลเดิมซ้ำ
jobId
รหัสงาน· ค่าตั้งต้น ไม่ส่งก็ได้
ใช้รอต่อ ไม่สร้างใหม่ ไม่เสียดาวเพิ่ม

ตั้งแต่นี้ไป เราเก็บสิ่งที่ผู้เรียกส่งมาจริงไว้กับงานด้วย แยกจากค่าที่ใช้จริงหลังเติมค่าตั้งต้น เพื่อให้ตอบได้ว่าฟิลด์ไหนถูกส่งมาและฟิลด์ไหนไม่ได้ส่ง

ถ้าให้ AI เป็นคนเรียก

ทุกข้อข้างล่างคือความผิดพลาดที่เกิดขึ้นจริงกับบริการนี้มาแล้ว วางไว้ใน system prompt ของเอเจนต์ได้เลย

ตัวอย่างที่ผิดกับที่ถูก

  ผิด     { "prompt": "a vertical 9:16 clip of a cat" }
          -> ได้คลิปแนวนอน prompt ไม่เคยถูกอ่านเพื่อหาสัดส่วน

  ถูก     { "prompt": "a cat", "aspect": "9:16" }
          -> ได้คลิป 720x1280

ส่งภาพเข้าไป

ส่งเป็นลิงก์หรือเป็น handle ที่เก็บไว้แล้ว อย่าส่งเป็นไบต์ · เพดานคือ 3,670,016 ตัวอักษรรวมทุกใบในคำขอเดียว ไม่ใช่ต่อใบ และ base64 ทำให้ใหญ่ขึ้นราว 1.37 เท่า · เกินแล้วเราเป็นคนปฏิเสธเอง ด้วยคำของเราและรหัส imagesTooLarge ซึ่งตั้งใจให้ต่ำกว่าเพดานของโฮสต์ เพราะถ้าปล่อยให้โฮสต์ปฏิเสธ คุณจะได้หน้าเปล่าที่ไม่มีใครที่นี่เขียน

ระวังตรงนี้: ref:x โคลอนเดียว คือ handle ที่เก็บไว้ · ref://x สองสแลช คือ control string คนละความหมายกันคนละขั้ว ต่างกันแค่สแลช · ส่วนสตริงที่ไม่ตรง prefix ไหนเลย รวมลิงก์ https:// ธรรมดา จะถูกนับเป็นไฟล์อัปโหลด ซึ่งใช้ได้ปกติ — พออ่านงานครั้งแรก ระบบจะจำมันเป็น handle ให้เอง แล้วลองใหม่ได้ · ที่ลองใหม่ไม่ได้คืองานที่ตายก่อนผู้ให้บริการจะรายงานอะไรกลับมา เพราะไม่เหลืออะไรให้ส่งซ้ำ

ส่งรูปจากเครื่องเข้ามา

POST /api/uploads พร้อมไฟล์ · ส่งได้สองแบบ multipart ฟิลด์ชื่อ file หรือ raw body ที่ตั้ง content-type เป็น image/… · ตอบกลับเป็น {"id":"file:…"} เอา id นั้นใส่ใน images ได้เลย เหมือน ref: ทุกอย่าง · รับ JPEG PNG WebP GIF โดยดูจากเนื้อไฟล์จริง ไม่ใช่จากชนิดที่ประกาศมา

  curl -F [email protected] -H "Authorization: Bearer <วางคีย์ของคุณตรงนี้>" https://gentook.example/api/uploads
  -> {"id":"file:k7m2x9p…","size":812340,"mimeType":"image/jpeg"}

ทำไมต้องมี: ทางเดิมคือใส่ base64 ลงในคำขอ ซึ่งเบราว์เซอร์ทำได้สบายเพราะหน้าเว็บถือไบต์ไว้ให้ แต่ agent ทำไม่ได้ — ทุก tool call คือตัวอักษรที่มันต้องพิมพ์เอง และรูป 768px คือหกหมื่นตัวอักษร · มีคนออกแบบคลิปใหม่ทั้งเรื่องให้ไม่มีหน้าคนสักเฟรม เพราะแนบรูปเดียวไม่ได้ · ทาง MCP ขอ transfer_ticket แบบ upload แล้วจะได้คำสั่ง curl ที่ไม่ต้องมีคีย์ ไฟล์วิ่งจากดิสก์มาที่เราตรงๆ ไม่ผ่านตัว agent เลย

รูปที่อัปเข้ามาเป็นห้องพักคอย ไม่ใช่คลัง · พองานแรกที่ใช้มันเสร็จ ผู้ให้บริการจะคืนรหัสมา ระบบสลับ handle เป็น ref: ให้เอง แล้วสำเนาฝั่งเราก็เลิกจำเป็น · เก็บได้พร้อมกันสูงสุด 20 ใบที่ยังไม่ได้ใช้ และของเก่ากว่าเจ็ดวันที่ไม่มีงานค้างอ้างถึงจะถูกกวาดทิ้ง · รูปของงานที่สร้างไม่สำเร็จจะถูกเก็บไว้ให้สั่งใหม่ได้ จึงยังนับโควตาอยู่ · ดูใบที่ค้างได้ที่ GET /api/uploads หรือหน้าคลังภาพอ้างอิง หัวข้อ 'อัปไว้แล้ว ยังไม่ได้ใช้' · ลบทีละใบด้วย DELETE /api/uploads/file:<id> ฝั่ง MCP ใช้ delete_picture

ไม่มีช่อง negative prompt

อยากไม่ให้มีอะไร เขียนลงในคำสั่งปกติเลย เช่น "ชามผลไม้บนโต๊ะไม้ ไม่เอาสีแดง" · ตัวเจนที่อยู่ข้างหลังนี่อ่านประโยคเดียว ไม่มีช่องที่สอง

ถามผู้ให้บริการตรง ๆ แล้ว: มันรับ negativePrompt โดยไม่บ่น แต่มันก็รับชื่อฟิลด์ที่ไม่มีใครเคยเขียนขึ้นมาเหมือนกัน การรับจึงแปลว่าอ่านบอดี้ออกเท่านั้น ไม่ได้แปลว่ารองรับ · ในเอกสารของมันก็ไม่มีคำนี้ และคำขอเดิมเป๊ะสองครั้งยังได้คนละภาพ จึงไม่มีทางวัดว่ามันทำอะไรหรือเปล่า · เขียนไว้ตรงนี้เพื่อจะได้ไม่มีใครต้องเสียเวลาไปหาซ้ำ

เมื่องานล้ม

อ่าน errorKind ไม่ใช่ error · error คือคำพูดของ gateway เอง เอาไว้ให้คนอ่าน ไม่ใช่เอาไว้ให้โปรแกรมแยกกรณี

filtered
คำที่ใช้ถูกปฏิเสธ ส่งซ้ำก็ถูกปฏิเสธอีก ต้องเปลี่ยนคำ อย่าลองใหม่
busy
ตัวเจนปฏิเสธรอบนี้ชั่วคราว รออีกนาทีแล้วลองใหม่ ไม่เกินสองครั้ง
timeout
ใช้เวลานานเกิน ลองใหม่หนึ่งครั้ง หรือขอของที่ง่ายกว่า
refGone
ภาพที่ใช้เป็นต้นทางหายถาวร อย่าลองใหม่ ให้เจนใหม่ทั้งชิ้น
refUnreachable
ดึงภาพต้นทางไม่ได้ในรอบนี้ ลองใหม่หนึ่งครั้งแล้วหยุด
failed
ไม่เข้ารูปแบบไหนเลย เอาข้อความใน error ให้คนอ่านแล้วหยุด

รหัสความผิดพลาด

ความล้มเหลวเป็น JSON ที่มี error เสมอ และ ส่วนใหญ่ มี code มาด้วย — แต่ไม่ใช่ทุกครั้ง การปฏิเสธเพราะคำขอผิดรูปทั่วไปมีแต่ error เปล่า ๆ · และ 502 ของ POST /api/generate เป็นอีกแบบ มันรายงานแยกรายงาน โดยใส่ไว้ใน jobs[].error ของแต่ละงาน ไม่ใช่ที่ระดับบนสุด · รหัสที่คุณไม่รู้จัก และกรณีที่ไม่มีรหัสมาเลย ให้ถือว่า “หยุดแล้วบอกคน” เสมอ ห้ามถือว่าลองใหม่ได้

imagesTooLarge
ภาพที่แนบมารวมกันใหญ่เกินเพดาน ส่งเป็นลิงก์หรือ handle แทนไบต์
notEnoughStars
ดาวไม่พอ ไปเติมที่หน้าเว็บ อย่าลองใหม่
starsRestricted
มีดาว แต่เป็นประเภทที่รุ่นนี้ไม่รับ (เช่น ดาวต้อนรับ) เติมดาวหรือเลือกรุ่นอื่น อย่าลองใหม่
keyDailyCap
คีย์ใบนี้ชนเพดานรายวันที่เจ้าของตั้งไว้ รอวันถัดไป
maintenance
ปิดปรับปรุงชั่วคราว คีย์ไม่ได้มีปัญหา ลองใหม่ทีหลัง
signin
อ่านคีย์จาก header ไม่ได้เลย ตรวจว่าเป็น Authorization: Bearer <คีย์> เป๊ะ ๆ
apiKey
คีย์ผิดหรือถูกเพิกถอนแล้ว หยุดแล้วบอกคน
apiKeyScope
คีย์ใบนี้ไม่ได้รับสิทธิ์นั้น หยุด อย่าลองใหม่
suspended
บัญชีนี้ถูกระงับ หยุดแล้วบอกคน
windowClosed
ผลงานพ้นหน้าต่างเวลาแล้ว ต้องเจนใหม่
linkExpired
ที่เก็บไฟล์ฝั่งผู้ให้บริการไม่ต่ออายุลิงก์ให้ รออีกนาทีแล้วอ่านงานใหม่ ถ้ายังเป็นอีกต้องเจนใหม่
download
ดึงไฟล์ไม่ได้ในตอนนี้ ลองใหม่หนึ่งครั้ง
provider
ตัวเจนกำลังยุ่ง ลองใหม่ในอีกนาที
server
ฝั่งเราพัง ลองใหม่หนึ่งครั้งแล้วหยุด

ต่อผ่าน MCP

ค่าที่ก๊อปไปวางได้อยู่ในหน้าคีย์ ทั้งของ Claude Code, Codex และแอปที่ตั้งค่าด้วยไฟล์ JSON · ส่วนแอปที่พูดได้แต่ stdio ให้ผ่านตัวกลางข้างล่างนี้ ไม่ต้องแก้อะไรฝั่งเรา

claude.ai, ChatGPT และ Claude Desktop ไม่ต้องใช้คีย์เลย — เพิ่ม https://gentook.com/api/mcp เป็น custom connector แล้วล็อกอิน Gentook เมื่อถูกถาม ระบบจะออกคีย์ให้แอปนั้นเอง เห็นและเพิกถอนได้ในหน้าคีย์

สำหรับแอปที่รองรับแต่ stdio

npx mcp-remote https://gentook.example/api/mcp --header "Authorization: Bearer <วางคีย์ของคุณตรงนี้>"
เอกสาร API และ MCP · Gentook