샌드고 인증은 두 단계입니다. **키로 토큰을 받고, 토큰으로 발송한다.**

거의 모든 경우 이 문서를 읽을 필요가 없습니다 — 공식 SDK 가 전부 대신 처리합니다. REST 를 직접 호출하거나, SDK 가 없는 언어에서 클라이언트를 만들 때만 필요합니다.

## 준비물

샌드고 콘솔 → **연동 관리 → 앱**에서 발급받은 `accessKey` 와 `secretKey`.

```bash
export SENDGO_ACCESS_KEY=your_access_key
export SENDGO_SECRET_KEY=your_secret_key
```

두 값은 계정의 발송 권한 전체를 가집니다. 저장소에 커밋하지 마세요. 실수로 커밋했다면 콘솔에서 **폐기 후 재발급**해야 합니다 — 커밋을 되돌리는 것만으로는 노출이 사라지지 않습니다.

## 토큰 발급

`accessKey:secretKey` 를 Base64 로 인코딩해 Basic 인증 헤더로 보냅니다.

```bash
curl -X POST https://sendgo.io/api/v2/token \
  -H "Authorization: Basic $(printf '%s:%s' "$SENDGO_ACCESS_KEY" "$SENDGO_SECRET_KEY" | base64)"
```

```json
{
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
```

## 발급받은 토큰으로 호출

이후 모든 요청은 Bearer 인증을 씁니다. **v1 과 v2 의 값이 다릅니다.**

| 버전 | 헤더 |
| --- | --- |
| v1 | `Authorization: Bearer base64(token)` |
| v2 | `Authorization: Bearer token` |

v1 에서 토큰을 한 번 더 인코딩하지 않으면 401 이 돌아옵니다. 신규 연동은 **v2** 를 쓰세요.

```bash
curl -X POST https://sendgo.io/api/v2/notices/send \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "templateCode": "ORDER_CONFIRM_001",
    "scheduleType": "DIRECTLY",
    "kakaoSenderKey": "your_kakao_sender_key",
    "senderKey": "your_sms_sender_key",
    "contacts": [{ "contact": "01012345678", "var1": "ORD-001" }]
  }'
```

## SDK 를 쓸 때

키만 넘기면 끝입니다. 토큰 발급, 캐싱, 만료 시 재발급, 401/403 재시도가 모두 안에서 처리됩니다.

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

const sendgo = new Sendgo({
  accessKey:  process.env.SENDGO_ACCESS_KEY!,
  secretKey:  process.env.SENDGO_SECRET_KEY!,
  apiVersion: 'v2',
});
// 토큰 관련 코드는 없습니다. 첫 발송 때 알아서 받아옵니다.
```

```python
from sendgo import Sendgo

client = Sendgo(
    access_key=os.environ["SENDGO_ACCESS_KEY"],
    secret_key=os.environ["SENDGO_SECRET_KEY"],
    api_version="v2",
)
```

```php
<?php

$sendgo = new Sendgo\Php\Sendgo([
    'access_key'  => $_ENV['SENDGO_ACCESS_KEY'],
    'secret_key'  => $_ENV['SENDGO_SECRET_KEY'],
    'api_version' => 'v2',
]);
```

```go
client, err := sendgo.New(sendgo.Config{
    AccessKey:  os.Getenv("SENDGO_ACCESS_KEY"),
    SecretKey:  os.Getenv("SENDGO_SECRET_KEY"),
    ApiVersion: "v2",
})
```

**클라이언트는 한 번 만들어 재사용하세요.** 요청마다 새로 만들면 캐시된 토큰이 버려지고 매번 토큰을 새로 발급받게 됩니다. Laravel·Spring·NestJS 확장은 싱글턴으로 등록하므로 이 문제가 없습니다.

## 인증 오류

| 코드 | HTTP | 원인 |
| --- | --- | --- |
| `INVALID_ACCESS_KEY` | 401 | 액세스 키가 존재하지 않거나 시크릿이 틀림 |
| `ACCESS_KEY_NOT_APPROVED` | 403 | 앱이 아직 승인 대기 상태 |
| `IP_NOT_ALLOWED` | 403 | 앱에 설정한 허용 IP 밖에서 호출 |

`IP_NOT_ALLOWED` 는 로컬에서 개발할 때 자주 만납니다. 개발 환경에서는 허용 IP 를 비워 두거나 개발자 IP 를 추가하세요. 서버 IP 는 배포 후 실제 아웃바운드 IP 로 확인해야 합니다 — NAT 게이트웨이나 로드밸런서 뒤라면 인스턴스 IP 와 다릅니다.

## 다음 단계

- [5분 만에 첫 알림톡 발송하기](/ko/cookbook/quickstart)
- [오류 코드와 재시도 전략](/ko/cookbook/error-handling)