{"openapi":"3.0.0","info":{"title":"Zalo OA SaaS — API công khai","version":"1.0.0","description":"Xác thực bằng `client_credentials` (xem `POST /v1/auth/token`) — mỗi request kèm `Authorization: Bearer <token>`.\n\n**Header phản hồi trên mọi route** (trừ `/v1/auth/token`, `/v1/health`): `X-Request-Id`, `X-RateLimit-Limit`/`X-RateLimit-Remaining`/`X-RateLimit-Reset`, `X-Quota-Used`/`X-Quota-Limit`.\n\n`Idempotency-Key` **bắt buộc** trên mọi `POST`/`PATCH` — gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.\n\nWebhook ra (sự kiện `message.sent`, `message.delivered`, `message.seen`, `message.failed`, `campaign.completed`, `contact.opted_out`, `oa.token_error`, `quota.threshold_reached`) ký bằng `X-Signature: sha256=HMAC_SHA256(secret, timestamp + \".\" + rawBody)` — cấu hình endpoint trong web app, mục Tích hợp."},"servers":[{"url":"https://api.phanmempanda.com"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Token client_credentials lấy từ POST /v1/auth/token, TTL 1 giờ. Ký cùng thuật toán JWT phiên đăng nhập nhưng KHÔNG dùng lẫn được (claim principal khác nhau)."}},"schemas":{"ApiClientTokenResult":{"type":"object","properties":{"accessToken":{"type":"string"},"tokenType":{"type":"string","enum":["Bearer"]},"expiresIn":{"type":"number","example":3600}},"required":["accessToken","tokenType","expiresIn"]},"ErrorResponse":{"type":"object","properties":{"message":{"type":"string","example":"Yêu cầu không hợp lệ"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"required":["field","code","message"]}}},"required":["message"]},"SendMessagePublicResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","example":"queued"},"routing_decision":{"nullable":true},"zalo_cost_estimated":{"type":"number","nullable":true},"billable_units":{"type":"number"}},"required":["id","status","routing_decision","zalo_cost_estimated","billable_units"]},"SendBulkPublicResponse":{"type":"object","properties":{"status":{"type":"string","enum":["accepted"]},"count":{"type":"number"},"ids":{"type":"array","items":{"type":"string"}}},"required":["status","count","ids"]}},"parameters":{}},"paths":{"/v1/auth/token":{"post":{"summary":"Cấp access token bằng client_credentials","tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["client_credentials"]},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1}},"required":["grant_type","client_id","client_secret"]}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiClientTokenResult"}}}},"401":{"description":"Sai client_id/client_secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/health":{"get":{"summary":"Kiểm tra API còn sống","tags":["Health"],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"]}}}}}}},"/v1/messages/send":{"post":{"summary":"Gửi 1 tin nhắn","tags":["Messages"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"oa_code":{"type":"string","minLength":1,"maxLength":32},"template_id":{"type":"string","minLength":1,"maxLength":64},"phone":{"type":"string","minLength":1,"maxLength":20},"params":{"type":"object","additionalProperties":{"type":"string"},"default":{}},"routing":{"type":"object","properties":{"mode":{"type":"string","enum":["auto","uid_only","phone_only"],"default":"auto"}},"default":{"mode":"auto"}},"schedule_send_at":{"type":"string","nullable":true},"tracking":{"type":"string","maxLength":128}},"required":["oa_code","template_id","phone"]}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessagePublicResponse"}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/messages/send-bulk":{"post":{"summary":"Gửi hàng loạt (tối đa 5.000 tin/request)","tags":["Messages"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"oa_code":{"type":"string","minLength":1,"maxLength":32},"template_id":{"type":"string","minLength":1,"maxLength":64},"routing":{"type":"object","properties":{"mode":{"type":"string","enum":["auto","uid_only","phone_only"],"default":"auto"}},"default":{"mode":"auto"}},"messages":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"params":{"type":"object","additionalProperties":{"type":"string"},"default":{}},"tracking":{"type":"string","maxLength":128},"schedule_send_at":{"type":"string","nullable":true}},"required":["phone"]},"minItems":1,"maxItems":5000}},"required":["oa_code","template_id","messages"]}}}},"responses":{"202":{"description":"Đã nhận, đang xử lý nền","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBulkPublicResponse"}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/messages":{"get":{"summary":"Tìm tin nhắn","tags":["Messages"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":20},"required":false,"name":"phone","in":"query"},{"schema":{"type":"string","maxLength":128},"required":false,"name":"tracking","in":"query"},{"schema":{"type":"string","maxLength":32},"required":false,"name":"oaCode","in":"query"},{"schema":{"type":"string","maxLength":64},"required":false,"name":"templateId","in":"query"},{"schema":{"type":"integer","nullable":true},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","nullable":true},"required":false,"name":"createdFrom","in":"query"},{"schema":{"type":"string","nullable":true},"required":false,"name":"createdTo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"number"},"phone":{"type":"string","example":"0912***678"},"oa_account_id":{"type":"string"},"template_id":{"type":"string"},"tracking":{"type":"string","nullable":true},"campaign_id":{"type":"string","nullable":true},"error_message":{"type":"string","nullable":true},"zalo_message_id":{"type":"string","nullable":true},"sent_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","status","phone","oa_account_id","template_id","tracking","campaign_id","error_message","zalo_message_id","sent_at","created_at"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/messages/{id}":{"get":{"summary":"Xem chi tiết 1 tin nhắn","tags":["Messages"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"number"},"phone":{"type":"string"},"uid":{"type":"string","nullable":true},"routing_decision":{"nullable":true},"tracking":{"type":"string","nullable":true},"error_code":{"type":"string","nullable":true},"error_message":{"type":"string","nullable":true},"zalo_message_id":{"type":"string","nullable":true},"attempts":{"type":"array","items":{"nullable":true}}},"required":["id","status","phone","uid","tracking","error_code","error_message","zalo_message_id","attempts"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Không tìm thấy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/messages/{id}/cancel":{"patch":{"summary":"Huỷ 1 tin đang chờ gửi","tags":["Messages"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"number"}},"required":["id","status"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns":{"get":{"summary":"Liệt kê chiến dịch","tags":["Campaigns"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"status":{"type":"number"},"type":{"type":"number"},"oa_account_id":{"type":"string"},"template_id":{"type":"string"},"audience_type":{"type":"number"},"mode":{"type":"string"},"routing_mode":{"type":"number"},"stats":{"nullable":true},"zalo_cost":{"nullable":true},"billable_units":{"type":"number"},"created_at":{"type":"string"}},"required":["id","code","name","status","type","oa_account_id","template_id","audience_type","mode","routing_mode","billable_units","created_at"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{code}":{"get":{"summary":"Xem chi tiết 1 chiến dịch","tags":["Campaigns"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"CAMP-001"},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"status":{"type":"number"},"type":{"type":"number"},"oa_account_id":{"type":"string"},"template_id":{"type":"string"},"audience_type":{"type":"number"},"mode":{"type":"string"},"routing_mode":{"type":"number"},"stats":{"nullable":true},"zalo_cost":{"nullable":true},"billable_units":{"type":"number"},"created_at":{"type":"string"}},"required":["id","code","name","status","type","oa_account_id","template_id","audience_type","mode","routing_mode","billable_units","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Thành công","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{code}/cancel":{"patch":{"summary":"Huỷ 1 chiến dịch đang gửi","tags":["Campaigns"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"CAMP-001"},"required":true,"name":"code","in":"path"},{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"status":{"type":"number"},"type":{"type":"number"},"oa_account_id":{"type":"string"},"template_id":{"type":"string"},"audience_type":{"type":"number"},"mode":{"type":"string"},"routing_mode":{"type":"number"},"stats":{"nullable":true},"zalo_cost":{"nullable":true},"billable_units":{"type":"number"},"created_at":{"type":"string"}},"required":["id","code","name","status","type","oa_account_id","template_id","audience_type","mode","routing_mode","billable_units","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/oa-accounts":{"get":{"summary":"Liệt kê Official Account đã kết nối","tags":["OA accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string","nullable":true},"status":{"type":"number"},"daily_quota":{"type":"number","nullable":true},"remaining_quota":{"type":"number","nullable":true},"oa_quality":{"type":"string","nullable":true}},"required":["id","code","name","status","daily_quota","remaining_quota","oa_quality"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/templates":{"get":{"summary":"Liệt kê mẫu tin đã đồng bộ từ Zalo","tags":["Templates"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":32},"required":false,"name":"oaCode","in":"query"},{"schema":{"type":"integer","nullable":true},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"oa_account_id":{"type":"string"},"template_id":{"type":"string"},"name":{"type":"string"},"tag":{"type":"string"},"status":{"type":"number"},"quality":{"type":"string","nullable":true},"params":{"type":"array","items":{"nullable":true}},"zalo_price":{"type":"number","nullable":true},"zalo_price_uid":{"type":"number","nullable":true},"supports_uid":{"type":"boolean"}},"required":["id","oa_account_id","template_id","name","tag","status","quality","params","zalo_price","zalo_price_uid","supports_uid"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/segments":{"get":{"summary":"Liệt kê phân khúc liên hệ","tags":["Segments"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"conditions":{"nullable":true},"is_dynamic":{"type":"boolean"},"cached_count":{"type":"number","nullable":true}},"required":["id","name","is_dynamic","cached_count"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/contacts":{"get":{"summary":"Tìm liên hệ trong sổ địa chỉ","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":20},"required":false,"name":"phone","in":"query"},{"schema":{"type":"string","maxLength":64},"required":false,"name":"tag","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"optedOut","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"attributes":{"type":"object","additionalProperties":{"nullable":true}},"tags":{"type":"array","items":{"type":"string"}},"opted_out":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","phone","name","email","attributes","tags","opted_out","created_at"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Tạo 1 liên hệ","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","maxLength":255},"email":{"type":"string","maxLength":255,"format":"email"},"attributes":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"default":{}},"tags":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50,"default":[]}},"required":["phone"]}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"attributes":{"type":"object","additionalProperties":{"nullable":true}},"tags":{"type":"array","items":{"type":"string"}},"opted_out":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","phone","name","email","attributes","tags","opted_out","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/contacts/{id}":{"get":{"summary":"Xem chi tiết 1 liên hệ","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"attributes":{"type":"object","additionalProperties":{"nullable":true}},"tags":{"type":"array","items":{"type":"string"}},"opted_out":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","phone","name","email","attributes","tags","opted_out","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Thành công","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"summary":"Cập nhật 1 liên hệ","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","maxLength":255},"email":{"type":"string","maxLength":255,"format":"email"},"attributes":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"default":{}},"tags":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50,"default":[]},"optedOut":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"attributes":{"type":"object","additionalProperties":{"nullable":true}},"tags":{"type":"array","items":{"type":"string"}},"opted_out":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","phone","name","email","attributes","tags","opted_out","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"summary":"Xoá mềm 1 liên hệ","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/contacts/bulk-upsert":{"post":{"summary":"Tạo/cập nhật hàng loạt liên hệ (tối đa 1.000/request)","tags":["Contacts"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","maxLength":255},"email":{"type":"string","maxLength":255,"format":"email"},"attributes":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"default":{}},"tags":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50,"default":[]}},"required":["phone"]},"minItems":1,"maxItems":1000}},"required":["contacts"]}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"upserted":{"type":"number"},"invalid":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string"},"reason":{"type":"string"}},"required":["phone","reason"]}}},"required":["upserted","invalid"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/blacklists":{"get":{"summary":"Liệt kê số điện thoại bị chặn","tags":["Blacklists"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"scope":{"type":"number","description":"1=mọi tin, 2=chỉ tin hậu mãi"},"reason":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","phone","scope","reason","expires_at","created_at"]}}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Chặn 1 số điện thoại","tags":["Blacklists"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"scope":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"default":1},"reason":{"type":"string","maxLength":500},"expiresAt":{"type":"string","nullable":true}},"required":["phone"]}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"scope":{"type":"number","description":"1=mọi tin, 2=chỉ tin hậu mãi"},"reason":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","phone","scope","reason","expires_at","created_at"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/blacklists/{id}":{"delete":{"summary":"Bỏ chặn","tags":["Blacklists"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/automations/{id}/trigger":{"post":{"summary":"Kích hoạt 1 kịch bản tự động (trigger loại webhook)","tags":["Automations"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"01J9XABCDEF1234567890"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Bắt buộc cho mọi POST/PATCH. Gọi lại đúng key trong 24h trả về nguyên response cũ, không tạo thêm bản ghi.","example":"order-2026-08-27-000123"},"required":true,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"contact_id":{"type":"string","minLength":1},"phone":{"type":"string","minLength":1,"maxLength":20},"event_id":{"type":"string","minLength":1,"maxLength":64}}}}}},"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"runId":{"type":"string","nullable":true}},"required":["runId"],"description":"runId=null nghĩa là event_id đã kích hoạt trước đó (chống trùng)"}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/usage":{"get":{"summary":"Xem hạn mức/đã dùng kỳ hiện tại","tags":["Usage"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"period_start":{"type":"string"},"period_end":{"type":"string"},"messages":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number","nullable":true},"warning":{"type":"boolean"}},"required":["used","limit","warning"]},"contacts":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number","nullable":true},"warning":{"type":"boolean"}},"required":["used","limit","warning"]},"oa":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number","nullable":true},"warning":{"type":"boolean"}},"required":["used","limit","warning"]},"users":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number","nullable":true},"warning":{"type":"boolean"}},"required":["used","limit","warning"]},"automations":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number","nullable":true},"warning":{"type":"boolean"}},"required":["used","limit","warning"]}},"required":["period_start","period_end","messages","contacts","oa","users","automations"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/reports/summary":{"get":{"summary":"Báo cáo tổng quan (theo ngày/OA/mẫu tin)","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","nullable":true},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","nullable":true},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"Thành công","content":{"application/json":{"schema":{"type":"object","properties":{"totals":{"type":"object","properties":{"total":{"type":"number"},"delivered":{"type":"number"},"seen":{"type":"number"},"failed":{"type":"number"},"delivered_rate":{"type":"number"},"seen_rate":{"type":"number"}},"required":["total","delivered","seen","failed","delivered_rate","seen_rate"]},"by_day":{"type":"array","items":{"nullable":true}},"by_oa":{"type":"array","items":{"nullable":true}},"by_template":{"type":"array","items":{"nullable":true}}},"required":["totals","by_day","by_oa","by_template"]}}}},"400":{"description":"Yêu cầu không hợp lệ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Thiếu hoặc sai access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Thiếu scope cần thiết","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Vượt X-RateLimit-Limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}