Trong 1 dòng: Bạn gọi 1 lệnh → Server xác thực danh tính → 1 AI viết bài → AI thứ 2 chấm điểm độc lập → Hệ thống tự quyết giao bài hay gợi ý sửa → Bạn nhận content.
1. Đăng ký2. Bạn gọi API3. Server kiểm tra4. Writer viết5. Reviewer chấm6. Auto-quyết7. Bạn nhận

Tại sao 6/10, không 8/10?

Trước khi đi sâu vào từng bước, có 1 câu hỏi bạn sẽ thắc mắc: "Sao chất lượng tối thiểu chỉ 6/10? Nghe thấp vậy?"

Đây là điểm quan trọng nên mình giải thích sớm — không phải con số tự bịa. 6/10 là điểm cân bằng rút ra sau khi test trên hàng ngàn bài viết thực tế:

  • Đặt cao hơn (vd 8/10): reviewer khắt khe quá, nhiều bài đáng được giao lại bị reject. Bạn phải retry, mất thời gian, bực mình.
  • Đặt thấp hơn (vd 4/10): quá nhiều bài tệ lọt qua, bạn nhận về rồi mất niềm tin vào hệ thống.
  • 6/10: vừa đủ. Output ở mức 6+ rất hiếm khi cần reject — bạn thường chỉ tweak nhẹ là đăng được luôn.

Và nó còn kết hợp với điều kiện "AND" — nghĩa là cả 2 phải cùng đúng: verdict = APPROVE score ≥ 6. Không có chuyện "score 9 nhưng verdict REJECT vẫn được duyệt" — hai điều kiện phải cùng pass.

Cái hay ở đây là: nếu score < 6 hoặc verdict = REJECT → job không tính quota. Bạn không mất gì khi hệ thống reject. Đây là risk reversal cốt lõi của pipeline.

Nói thật là 6/10 không phải "đủ tốt." 6/10 là điểm mà data chứng minh: output sẽ xài được trong gần 100% trường hợp. Cao hơn nữa là khắt khe quá. Thấp hơn nữa là ẩu.
Prep 1
Lấy key
Đăng ký 1 phút — nhận key
Nhập email tại /register → xác thực → bấm link → API key hiện ra 1 lần duy nhất, copy + lưu lại. Key có dạng capi_xxx… — không expire, có thể tạo nhiều key để revoke từng cái.
Free tier: 10 yêu cầu/tháng, không cần thẻ. Đủ để test caption hoặc marketing post trước khi quyết định mua.
Prep 2
Bạn gọi
3 cách gọi — pick one or mix
Playground (browser): Mở /playground trong dashboard → điền topic → click Generate. Không cài gì.
MCP (Claude Desktop / Cursor / VS Code): Gõ "viết caption về X" trong chat — Claude tự gọi tool write_content.
REST: POST /v1/content/generate với header x-api-key. Sau dùng GET /v1/content/{job_id} để kiểm tra.
6 loại content: caption · marketing · email · blog · article · landing. Free tier: caption + marketing only.
Phase 1
Server
kiểm tra
3 lớp kiểm tra — xảy ra trong < 50ms
Xác thực: Kiểm tra API key có tồn tại không. Sai key → từ chối ngay (401).
Kiểm quota: Đếm bài bạn đã viết tháng này — chỉ count pending / running / completed. Bài bị reject hoặc failed không tính → bạn không mất quota vào thất bại.
Kiểm schema: Topic/brief đúng định dạng không. Free tier giới hạn content type.
Pass cả 3 → server tạo job_id duy nhất → gửi vào queue chờ xử lý → trả 202 + job_id + thời gian dự kiến.
Phase 2
Writer
viết
Pass 1 — Writer: chỉ viết, KHÔNG tự chấm điểm
Input: topic + brief + voice profile của bạn (giọng, phong cách, quy tắc viết) + checklist theo tier.
Tier ảnh hưởng: basic → flash model nhanh (4–15s). upgrade/pro → pro model kỹ hơn (20–120s). Pro còn bật thinking mode — AI dành thêm thời gian suy nghĩ trước khi viết, output logic rõ hơn.
Output: draft hoàn chỉnh — đủ mở/thân/kết, đúng giọng, đúng độ dài.
Voice profile + prompts ở lại server. Bạn không thấy system prompt — người khác cũng không.
Phase 3
Reviewer
chấm
Pass 2 — Reviewer độc lập: không thấy logic của Writer
Tại sao tách 2 AI? Nếu cùng 1 model viết rồi tự chấm, có xu hướng "tự khen." Tách riêng → Reviewer không biết logic của Writer → chấm công bằng hơn.
Reviewer trả về:
Verdict APPROVE / REQUEST_CHANGES / REJECT
Score 0–10 (giọng chuẩn không)
Issues danh sách điều cần sửa
Patches text gợi ý thay thế cụ thể
Phase 4
Auto-
quyết
Server tự quyết — bạn không cần duyệt tay
4 lối đi, ngưỡng rõ ràng (threshold 6/10 + AND logic):
✓ APPROVE
  • Verdict = APPROVE score ≥ 6/10
  • Cả 2 điều kiện phải đúng — đề phòng reviewer "APPROVE" ở score thấp
  • → Draft thành content final
🔧 REQUEST_CHANGES + patches
  • Patches[] khớp được text trong draft
  • Auto-apply patches (tự sửa, bạn không cần duyệt)
  • → Giao content đã sửa xong
📝 REQUEST_CHANGES — ship advisory
  • Patches không match được text trong draft
  • Vẫn giao content kèm issues[] gợi ý sửa
  • → Không phải REJECT — bạn vẫn nhận output dùng được
✗ REJECT
  • Verdict = REJECT, hoặc verdict = APPROVE nhưng score < 6
  • → Status = rejected, không tính quota
  • → Nhận issues[] → retry với brief tốt hơn
Nhắc nhanh: Lý do chốt 6/10 — xem Section "Tại sao 6/10, không 8/10?" ở trên. Ngắn gọn: 6/10 là điểm cân bằng từ test thực tế, và bài bị reject không tính quota.
Phase 5
Bạn
nhận
2 cách nhận — chọn theo workflow của bạn
Polling: Gọi GET /v1/content/{job_id} mỗi 3–5s cho đến khi status = completed. CLI và MCP làm tự động.
Webhook: Truyền URL webhook khi tạo job — server POST kết quả về URL bạn ngay khi xong. Header X-Content-Signature để verify origin. Retry 3 lần exponential backoff tự động.
Response bạn nhận:{ content, quality_score, voice_mode, tier, review_report, generated_at }
quality_score là snapshot từ lúc generate → audit trail không bị vỡ khi bạn update voice sau này.
🔒

Giọng được bảo vệ

Voice profile (samples, quy tắc viết) không bao giờ rời server. Không endpoint nào trả raw voice data. Khi bạn update voice, version cũ vẫn audit trail được — không sợ mất vết.

🎯

Quality gate độc lập

Writer viết, Reviewer chấm — 2 instance tách riêng với 2 prompt khác nhau. Threshold 6/10 + AND logic = không có chuyện "APPROVE ở score thấp." Auto-patch = sửa mà không cần bạn duyệt.

API mỗi nơi

MCP trên Claude Desktop / Cursor / VS Code. REST trên curl / Postman / script. Playground trên browser. 1 API key, mọi nơi — không cần học 3 cách khác nhau.

💸

Chỉ trả tiền khi dùng được

Quota chỉ tính jobs pending / running / completed. Rejected hay failed? Miễn phí. Bạn chỉ trả tiền cho output có giá trị, không trả cho retry.

Câu hỏi hay gặp

Free tier 10 request/tháng có đủ để test không?Đủ. 10 request đủ để bạn thử caption (free tier hỗ trợ) → xem quality_score → đọc review_report. Nếu thích pipeline, lên Starter để mở blog, article, landing.
AI viết bài blog mất bao lâu?Tuỳ tier. Caption basic: 4–15s. Marketing/email upgrade: 20–40s. Blog/article pro với thinking mode: 60–120s (AI dành thêm thời gian suy nghĩ). Thời gian dự kiến hiện ngay sau khi submit job.
Reviewer chấm dưới threshold thì sao?Threshold là 6/10. Nếu score < 6 (ví dụ 4/10 hoặc 5/10) hoặc verdict = REJECT → status = rejected. Bạn nhận review_report.issues chi tiết → biết cần fix gì → retry với brief rõ hơn. Job rejected không tính quota. Lưu ý: 7/10 với verdict APPROVE thì PASS (7 ≥ 6).
Làm sao upload voice của tôi?POST /v1/voices với 1–10 writing samples + hard_rules (vd: no_emoji). Server hash thành voice_version (SHA-1 snapshot). Mỗi lần generate snapshot version → audit trail. Khi update voice, version mới tự bump, old version vẫn lưu được.
Tôi có thể tự đổi reviewer threshold không?Hiện tại chốt ở 6/10 AND logic — đây là mặt mạnh (chất lượng nhất quán, không "APPROVE ở score thấp"). Nếu muốn reviewer nhẹ hơn, gọi với tier=basic (checklist đơn giản hơn).
Sao tách Writer và Reviewer thành 2 AI?Nếu cùng 1 model viết rồi tự chấm, có xu hướng tự khen (self-bias cao). Tách riêng → Reviewer không biết logic của Writer → chấm công bằng hơn. Latency chênh lệch (caption 4s vs blog 90s) là bằng chứng hai model chạy riêng biệt.
Webhook signature là gì? Có cần verify không?Webhook request có header X-Content-Signature: sha256={hex} — đó là chữ ký của request để bạn verify origin (không phải spam). Không verify cũng được, nhưng nên làm để an toàn hơn.
Rejected job không tính quota là sự thật hay marketing?Sự thật. Hệ thống chỉ count statuses pending, running, completed vào quota. rejectedfailed bị skip. Bạn có thể check GET /v1/auth/usage để thấy quota thực tế.

Tham chiếu kỹ thuật (cho dev)

REST endpointsPOST /v1/content/generate · GET /v1/content/:id · POST/GET/PUT /v1/voices
MCP endpointhttps://content-apiapi-production.up.railway.app/mcp (Streamable HTTP) · 3 tools: write_content, list_voices, get_content_status
Authx-api-key header hoặc Authorization: Bearer. Key raw chỉ hiện 1 lần khi tạo.
ModelsWriter: deepseek-v4-flash (basic) · deepseek-v4-pro (upgrade · pro). Pro tier set thinking: enabled + reasoning_effort: high.
Voice schema{ name, samples[], hard_rules[], mode_default } → hash thành voice_version SHA-1 (12 hex chars)
Voice modeA (storytelling) · B (principle) · C (analysis). Mode C ép checklist = analysis bất kể tier.
Decision gateAPPROVE khi verdict === "APPROVE" AND voice_score >= 6. REQUEST_CHANGES auto-patch via replaceAll. REQUEST_CHANGES no-match → ship với advisory. Reviewer fail → REJECT (fail closed).
Quota statusesCount: pending · running · completed. Free: rejected · failed.
QueueBullMQ trên Redis. Worker timeout 120s/job. Voice cache TTL 1h.
Webhook signatureX-Content-Signature: sha256=<hex> = HMAC-SHA256(raw_body, secret). Verify timingSafeEqual.
Webhook retry3 attempts, exponential backoff 1s · 2s · 4s. Body luôn được lưu — operators có thể replay.
Error codes400 validation · 401 auth · 403 tier · 404 not found · 429 quota · 503 queue unavailable
Audit fieldsResponse: voice_version (snapshot at generation) · quality_score · review_report · tier · voice_mode · generated_at

Sẵn sàng thử?

10 request miễn phí mỗi tháng. Không thẻ. Lấy key trong < 2 phút.

Lấy API key →