본문 바로가기
Documentation menu

A PRACTICAL GUIDE

Doing everything over the API — operations automation for resellers

Register Kakao channels, submit Alimtalk templates for review, file sender numbers, and sync opt-outs without ever sending anyone to sendgo.io. Includes webhook delivery of review outcomes.

이 문서의 목차
POST /api/v2/notice-templates

Sending has been an API from day one. Registration and review were not — attaching a Kakao channel, creating an Alimtalk template and submitting it, uploading sender number paperwork all meant someone logging into a console. For a business building a product on top of messaging that was the bottleneck: every new merchant meant "go over there, sign up, and register".

Not any more. Registration and review are API now. Your customers only see your screens.

What the API covers

Task Endpoint
Kakao channel verify / register / sync /v2/kakao-senders
Alimtalk template CRUD, review, approval cancel /v2/notice-templates
Brand message template CRUD /v2/brand-templates
Kakao image upload /v2/kakao-images/{type}
Sender number filing (all types) /v2/senders
SMS snippet templates /v2/message-templates
Opt-out (080) lookup /v2/rejected-numbers
Event webhook subscription /v2/webhook

Exactly one step still involves a person, and it happens on your screen: the Kakao channel verification code. Kakao texts it to the channel administrator and Sendgo cannot see it either. Your user types it into your form.

Subscribe to webhooks first

Registration and review are asynchronous. Set up delivery before you start.

curl -X PUT "https://sendgo.io/api/v2/webhook" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://reseller.example.com/hooks/sendgo"}'

The secret in that response is shown once. Store it immediately.

Verify signatures against the raw bytes:

app.post('/hooks/sendgo', express.raw({ type: 'application/json' }), (req, res) => {
    const expected = crypto
        .createHmac('sha256', process.env.SENDGO_WEBHOOK_SECRET)
        .update(req.body)          // raw bytes, not a re-encoded object
        .digest('hex');

    if (expected !== req.get('X-Sendgo-Signature')) return res.sendStatus(401);

    const { event, data, deliveryId } = JSON.parse(req.body.toString('utf8'));

    // The same event can arrive twice — dedupe on deliveryId.
    queue.add(event, { data, deliveryId });

    res.sendStatus(204);   // Process in a queue; slow handlers pile up retries.
});

Available events:

Event Fires when
sender.status_changed Sender number approved or rejected
notice_template.inspection_status_changed Alimtalk review result
kakao_sender.status_changed Channel blocked or dormant
kakao_sender.brand_message_status_changed Brand message M/N application result

Use POST /v2/webhook/test to confirm the wiring first.

Registering a Kakao channel

Two calls.

# Step 1 — Kakao texts a verification code to the channel administrator
curl -X POST "https://sendgo.io/api/v2/kakao-senders/token" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"yellowId":"@my-channel","phoneNumber":"01012345678"}'

The response does not contain the code. Collect it on your screen, then:

# Step 2 — create the sender profile
curl -X POST "https://sendgo.io/api/v2/kakao-senders" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "token": "123456",
        "yellowId": "@my-channel",
        "phoneNumber": "01012345678",
        "categoryCode": "001001"
      }'

Look up categoryCode with GET /api/v2/kakao-senders/categories. The kakaoSenderKey in the response is what every later Alimtalk and brand message call uses.

The prerequisites match the console — the channel must exist on Kakao Business and be converted to a business channel.

Re-read channel status on a schedule

If Kakao blocks a channel, sending starts failing quietly.

curl -X POST "https://sendgo.io/api/v2/kakao-senders/sync" \
  -H "Authorization: Bearer $TOKEN"

Run it daily from cron. Subscribing to kakao_sender.status_changed tells you the moment it changes.

Filing a sender number

Start by asking what each type requires.

curl "https://sendgo.io/api/v2/senders/number-types" \
  -H "Authorization: Bearer $TOKEN"

Every type can be filed over the API. For mobile types the console's PASS identity verification is replaced by an ID document that a Sendgo operator checks.

Type Identity check Required documents
personal_other (personal landline) none usage certificate
personal_mobile ID document usage certificate + ID
team_main (company landline / corporate phone) none usage certificate
team_representative_mobile ID document usage certificate + ID
team_emp_mobile ID document usage certificate + ID + employment certificate
team_other_company (delegated) none usage certificate + 5 delegation documents
curl -X POST "https://sendgo.io/api/v2/senders" \
  -H "Authorization: Bearer $TOKEN" \
  -F "senderAlias=Representative mobile" \
  -F "senderNumberType=team_representative_mobile" \
  -F "phoneE164=01012345678" \
  -F "[email protected]" \
  -F "[email protected]"

A filed number comes back PENDING. Numbers filed with documents are never auto-approved — unlike the console's PASS path, which approves personal and representative mobiles immediately. The result arrives as sender.status_changed.

On rejection, rejectionReason carries the reason. Show it to the user, fix the paperwork, file again.

Calling POST /api/v2/senders/validate first lets you report format and duplicate problems back immediately.

Alimtalk templates and review

curl -X POST "https://sendgo.io/api/v2/notice-templates" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "kakaoSenderKey": "abc1234567890def",
        "templateName": "Order received",
        "templateContent": "#{name}, order #{orderNo} has been received.",
        "templateMessageType": "BA",
        "templateEmphasizeType": "NONE",
        "categoryCode": "001001",
        "messagePurpose": "order_delivery",
        "legalBasis": "transaction",
        "benefitOrigin": "none",
        "expiryType": "none",
        "optInReviewConfirmed": true,
        "ctaClearConfirmed": true,
        "policyConfirmed": true
      }'

Those last seven fields are Sendgo's own policy gate, separate from Kakao's review, and the API does not bypass them. Reasons come back in errors.reasons and are safe to show the user verbatim. Wording that trips this gate is usually rejected by Kakao too — being told instantly beats waiting days.

curl -X POST "https://sendgo.io/api/v2/notice-templates/TPL-20260911-0001/inspection" \
  -H "Authorization: Bearer $TOKEN"

The outcome arrives as notice_template.inspection_status_changed. Without webhooks, poll /sync.

created    REG  ← cannot send
submitted  REQ  ← under Kakao review (cancellable)
approved   APR  ← can send
rejected   REJ  ← read comments, fix, resubmit

In practice 30 minutes to one business day. Do not block a deployment pipeline on it.

Templates with images

A brand message imageUrl must be a Kakao-hosted URL. Upload first, then use the URL you get back.

curl -X POST "https://sendgo.io/api/v2/kakao-images/default" \
  -H "Authorization: Bearer $TOKEN" \
  -F "[email protected]"
# → data.imageUrl

Alimtalk image templates take the file directly on the create call (multipart).

Syncing opt-outs

Advertising messages must not go to opted-out numbers. The send API filters them, but your own database needs the same state — otherwise you send and get filtered every time while your screen still says "subscribed".

curl "https://sendgo.io/api/v2/rejected-numbers?since=2026-09-01&count=500" \
  -H "Authorization: Bearer $TOKEN"

Daily is enough.

An onboarding flow that never leaves your product

  1. Tell the merchant to open a Kakao business channel (your screen)
  2. Take channel id + admin phone → POST /kakao-senders/token (automated)
  3. Verification-code screen → POST /kakao-senders (your screen + automated)
  4. Document upload screen → POST /senders (your screen + automated)
  5. Bulk-create your standard template set with POST /notice-templates (automated)
  6. Submit each with POST .../inspection (automated)
  7. Receive approvals by webhook and notify the merchant (automated)

sendgo.io never appears in that list.

Next steps

자주 묻는 질문

Can I complete the whole integration without sending customers to sendgo.io?
Yes. Kakao channel registration, sender number filing, Alimtalk and brand message template creation and review submission, SMS snippets and opt-out lookup are all v2 API. Your customers only ever see your screens.
Can mobile sender numbers be registered over the API?
Yes. The console uses PASS identity verification; the API takes an ID document (identityDocument) and a Sendgo operator verifies it instead. Numbers filed this way are never auto-approved — they always start PENDING and wait for operator review.
Can I register Alimtalk templates through the API?
Yes. POST /api/v2/notice-templates creates it and POST /api/v2/notice-templates/{templateCode}/inspection submits it. Kakao performs the review, so the result is not immediate — subscribe to notice_template.inspection_status_changed or poll /sync.
How do I receive review outcomes?
Subscribe with PUT /api/v2/webhook. Sender approvals, Alimtalk review results, channel blocks and brand message targeting outcomes are pushed to you. Signatures are HMAC-SHA256 in the X-Sendgo-Signature header and must be verified against the raw request bytes.
Is there anything a human still has to do?
One thing: the Kakao channel verification code. Kakao texts it to the channel administrator and Sendgo never sees it. But the user types it into your screen, so nobody visits sendgo.io.
What kind of account do I need?
Kakao-related endpoints (channels, Alimtalk templates, brand message templates, image upload) require a team-owned application. Sender numbers, SMS templates, opt-outs and webhooks work with personal accounts too.

이 문서에서 쓰는 패키지

관련 문서

Focus on building. Leave messaging to Sendgo.Back to top ↑