CP-Notify
Send email, SMS, Kakao AlimTalk, and push notifications through a single API. Provider-specific env vars and signature handling are abstracted away on the CP side.
Permissions
Enable notify.* scopes when you create your API key:
notify.email.sendnotify.sms.sendnotify.kakao.sendnotify.push.send
Common characteristics across the four channels
| Channel | Provider | Response time (p50) |
|---|---|---|
| Resend | ~600ms | |
| SMS | Twilio | ~800ms |
| Kakao | Solapi | ~1.2s |
| Push | Firebase FCM | ~400ms |
Per-channel rate limit (providers themselves rate-limit downstream):
| Channel | Limit |
|---|---|
| 200 / min | |
| SMS · Kakao · Push | 3000 / min |
Overflow returns 429 with Retry-After: 60. All send endpoints respond 201 Created on success.
Email example
POST
https://notify.cp-platform.com/notifications/emailexport async function sendWelcomeEmail(email: string) {
const res = await fetch("https://notify.cp-platform.com/notifications/email", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.CP_NOTIFY_API_KEY!,
},
body: JSON.stringify({
to: email,
subject: "Welcome",
html: "<h1>Glad to have you</h1>",
}),
});
// 201 = sent; anything else is failure (429 limit / 403 perm·IDOR / 502 provider down)
if (res.status !== 201) {
const err = await res.json().catch(() => ({}));
console.error("[notify]", res.status, err);
throw new Error(err.detail ?? "Email send failed");
}
return res.json(); // { id, status, channel, created_at }
}SMS / Kakao / Push
Auth and response shape are identical; only the body differs. All live at /notifications/{channel} (no /send suffix).
| Channel | Path | Required body |
|---|---|---|
| SMS | /notifications/sms | to (E.164 +8210...), text |
| Kakao | /notifications/kakao | to (E.164), template_id, variables |
| Push | /notifications/push | title, body, data? (device is the owner_id's FCM token) |
Full schemas: Reference.
Cost & quota
See Quota & Pricing. Check remaining quota before sending with GET /notifications/quotas.
Security
- Never expose the API key on the client — keep it server-only (
process.env.CP_NOTIFY_API_KEY) - owner_id-based IDOR defense — the body
user_idis ignored; the recipient is always the API key'sowner_id - Kakao
template_idwhitelist — only approved templates on your channel are callable; otherwise 403