Getting the first Kakao Alimtalk out takes five steps. Only the last one is code — the other four are **account setup you do once**.

> In a hurry? If steps 1–3 are already done, jump to [step 5](#step-5-send).

## Step 1 — Issue your API keys

Sign in to the [Sendgo console](https://sendgo.io) and create an app under **Integration → Apps**. You get an `accessKey` and a `secretKey`.

```bash
# .env
SENDGO_ACCESS_KEY=your_access_key
SENDGO_SECRET_KEY=your_secret_key
SENDGO_KAKAO_SENDER_KEY=your_kakao_sender_key
SENDGO_SMS_SENDER_KEY=your_sms_sender_key
SENDGO_API_VERSION=v2
```

These two values carry the full sending permission for the account. Keep them in the environment, never in the repository. If you have a fixed server IP, add an **IP allowlist** to the app — a leaked key is then useless from anywhere else.

## Step 2 — Register a sending number and Kakao channel

In South Korea you may only send from a **pre-registered number** (전기통신사업법). This is the step that delays integrations, because it needs document review and teams usually start it after the code is finished.

- **SMS sending number** — submit proof that the number belongs to you. Approval takes business days.
- **Kakao sender profile** — connect a KakaoTalk channel to Sendgo and you get a `kakaoSenderKey`. The channel must already be converted to a **business channel** in Kakao Business.

## Step 3 — Register and approve a template

An Alimtalk body is a **template approved in advance**. At send time you only fill in the blanks.

```text
[#{var2}] Your order is confirmed.

Order number: #{var1}
Total: #{var3}
```

Register that, get a **template code** such as `ORDER_CONFIRM_001`, and you are ready.

> Promotional wording is not approved as an Alimtalk template — informational only. For marketing, use Brand Message or an advertising SMS.

## Step 4 — Install the SDK

Framework packages pull their core in, so **do not install both**.

```bash
composer require sendgo/laravel      # Laravel
composer require sendgo/php          # plain PHP
npm install @sendgo/node             # Node.js / TypeScript
pip install sendgo-python            # Python
go get github.com/send-go/go         # Go
gem install sendgo                   # Ruby
dotnet add package Sendgo.SDK        # .NET
```

Full list and selection guide: [Choosing an SDK](/en/cookbook/choose-sdk).

## Step 5 — Send

Create the client once and reuse it. Put the sender keys on the client so you do not repeat them per call.

### Node.js / TypeScript

```typescript
import Sendgo from '@sendgo/node';

const sendgo = new Sendgo({
  accessKey:      process.env.SENDGO_ACCESS_KEY!,
  secretKey:      process.env.SENDGO_SECRET_KEY!,
  kakaoSenderKey: process.env.SENDGO_KAKAO_SENDER_KEY,
  smsSenderKey:   process.env.SENDGO_SMS_SENDER_KEY,
  apiVersion:     'v2',
});

await sendgo.alimtalk.send({
  templateCode: 'ORDER_CONFIRM_001',
  contacts: [
    { contact: '01012345678', name: 'Hong Gildong', var1: 'ORD-001', var3: '29,000원' },
  ],
});
```

`@sendgo/node` is a **default export**. `import { Sendgo } from '@sendgo/node'` does not work.

### Python

```python
import os
from sendgo import Sendgo

client = Sendgo(
    access_key=os.environ["SENDGO_ACCESS_KEY"],
    secret_key=os.environ["SENDGO_SECRET_KEY"],
    kakao_sender_key=os.environ.get("SENDGO_KAKAO_SENDER_KEY"),
    sms_sender_key=os.environ.get("SENDGO_SMS_SENDER_KEY"),
    api_version="v2",
)

client.alimtalk.send(
    template_code="ORDER_CONFIRM_001",
    contacts=[{"contact": "01012345678", "name": "Hong Gildong", "var1": "ORD-001"}],
)
```

### PHP

```php
<?php

use Sendgo\Php\Sendgo;

$sendgo = new Sendgo([
    'access_key'       => $_ENV['SENDGO_ACCESS_KEY'],
    'secret_key'       => $_ENV['SENDGO_SECRET_KEY'],
    'kakao_sender_key' => $_ENV['SENDGO_KAKAO_SENDER_KEY'],
    'sms_sender_key'   => $_ENV['SENDGO_SMS_SENDER_KEY'],
    'api_version'      => 'v2',
]);

$sendgo->alimtalk->send([
    'templateCode' => 'ORDER_CONFIRM_001',
    'contacts'     => [
        ['contact' => '01012345678', 'name' => 'Hong Gildong', 'var1' => 'ORD-001'],
    ],
]);
```

### Laravel

`sendgo/laravel` auto-registers its ServiceProvider, so inject the client directly.

```php
<?php

use Sendgo\Php\Sendgo;

class OrderController extends Controller
{
    public function __construct(private Sendgo $sendgo) {}

    public function confirm(Order $order)
    {
        $this->sendgo->alimtalk->send([
            'templateCode' => 'ORDER_CONFIRM_001',
            'contacts'     => [[
                'contact' => $order->user->phone,
                'name'    => $order->user->name,
                'var1'    => $order->number,
            ]],
        ]);

        return response()->json(['success' => true]);
    }
}
```

Push this onto a queue in production — an external API call inside the request cycle makes your own response time depend on Kakao's.

### Java

```java
import io.sendgo.*;
import io.sendgo.model.*;
import java.util.List;

SendgoClient sendgo = new SendgoClient(SendgoConfig.builder()
    .accessKey(System.getenv("SENDGO_ACCESS_KEY"))
    .secretKey(System.getenv("SENDGO_SECRET_KEY"))
    .kakaoSenderKey(System.getenv("SENDGO_KAKAO_SENDER_KEY"))
    .smsSenderKey(System.getenv("SENDGO_SMS_SENDER_KEY"))
    .apiVersion("v2")
    .build());

sendgo.alimtalk().send(AlimtalkRequest.builder()
    .templateCode("ORDER_CONFIRM_001")
    .contacts(List.of(
        Contact.builder().contact("01012345678").name("Hong Gildong").var1("ORD-001").build()
    ))
    .build());
```

### Go

```go
client, err := sendgo.New(sendgo.Config{
    AccessKey:      os.Getenv("SENDGO_ACCESS_KEY"),
    SecretKey:      os.Getenv("SENDGO_SECRET_KEY"),
    KakaoSenderKey: os.Getenv("SENDGO_KAKAO_SENDER_KEY"),
    SmsSenderKey:   os.Getenv("SENDGO_SMS_SENDER_KEY"),
    ApiVersion:     "v2",
})
if err != nil {
    log.Fatal(err)
}

_, err = client.Alimtalk.Send(sendgo.AlimtalkRequest{
    TemplateCode: "ORDER_CONFIRM_001",
    Contacts: []sendgo.Contact{
        {Contact: "01012345678", Name: "Hong Gildong", Var1: "ORD-001"},
    },
})
```

## If the first send failed

| Code | Meaning | Fix |
| --- | --- | --- |
| `INVALID_ACCESS_KEY` | Wrong key | Check the environment variables are actually loaded |
| `ACCESS_KEY_NOT_APPROVED` | App not approved yet | Check the app status in the console |
| `IP_NOT_ALLOWED` | Called from outside the allowlist | Add your server's outbound IP |
| `INVALID_TEMPLATE_CODE` | Unknown or unapproved template | Compare against the console; it must be **approved**, not pending |
| `INVALID_KAKAO_SENDER_KEY` | Wrong sender profile key | Recheck the key in the console |
| `EMPTY_CONTACTS` | Recipient array is empty | Make sure `contacts` is actually populated |
| `PAYMENT_REQUIRED` | Out of credit | Top up; retrying will not help |

Full list: [Error codes and retry strategy](/en/cookbook/error-handling).

## Next

- [Choosing an SDK](/en/cookbook/choose-sdk)
- [Send an Alimtalk — full reference](/en/cookbook/send-alimtalk)
- [Send SMS, LMS and MMS](/en/cookbook/send-sms)