개발팀이 커질수록 공지사항, 배포 알림, 에러 로그를 일일이 공유하는 건 비효율적이다. 대부분의 팀은 이미 Slack을 쓰고 있지만, 단순히 채팅만 한다. 실제로는 Slack Bot API를 통해 서버 이벤트를 자동으로 특정 채널에 보낼 수 있고, 사용자 액션에 반응하는 인터랙티브 버튼도 만들 수 있다는 걸 모르는 경우가 많다. 다만 공식 문서는 복잡하고, PHP 예제는 거의 없어서 어디서부터 시작해야 할지 막막하다. 이번 글에서는 Slack Bot API의 기초 개념부터 실전 구현까지, PHP로 직접 동작하는 예제를 통해 완벽하게 정리하겠다.

 

1단계: Slack App 생성 및 Bot Token 발급받기
Slack Bot을 만들려면 먼저 Slack Workspace에 App을 등록해야 한다. 이 과정에서 Bot이 채널에 메시지를 보낼 수 있는 권한(토큰)을 받는다.

Slack App 만드는 순서:

1. https://api.slack.com/apps 접속
2. "Create New App" → "From scratch" 클릭
3. App name: "MyBot" (자유롭게 입력)
4. Workspace 선택 (자신의 Workspace)
5. "Create App" 클릭

App이 생성되면 왼쪽 메뉴에서 "OAuth & Permissions"로 이동하자. 여기서 Bot이 할 수 있는 작업(스코프)을 설정한다.

필요한 스코프 추가:

"Scopes" 섹션에서 "Bot Token Scopes" → "Add an OAuth Scope" 클릭
다음 권한들을 추가하자:

- chat:write (메시지 전송)
- channels:read (채널 목록 조회)
- groups:read (프라이빗 채널 조회)
- users:read (사용자 정보 조회)

스코프를 추가했으면 "Install to Workspace" 버튼이 나타난다. 클릭하면 권한 승인을 요청한 후 Bot User OAuth Token을 발급받을 수 있다. 이 토큰은 PHP 코드에서 사용하므로 안전하게 보관하자. (절대 공개 저장소에 커밋하면 안 됨)

 

2단계: Slack Webhook이란 뭔가 - 두 가지 방식 비교
방식 Incoming Webhook Bot API (oauth token)
용도 외부 서비스에서 Slack으로 메시지 보내기 Bot이 능동적으로 여러 채널 관리
설정 난이도 쉬움 (URL만 생성) 조금 복잡 (토큰 + 권한 설정)
기능 기본 메시지만 가능 인터랙티브 메시지, 파일 업로드, 사용자 관리 등
PHP 예제 curl로 간단히 구현 가능 토큰 기반 API 호출

이 글에서는 Bot API(oauth token) 방식을 중심으로 설명한다. Webhook은 더 간단하지만 기능이 제한적이기 때문이다.

 

3단계: PHP에서 Slack Bot으로 메시지 보내기

가장 기본적인 작업은 Bot을 통해 특정 채널에 메시지를 보내는 것이다. chat.postMessage 메서드를 사용한다.

✗ 잘못된 코드 - 토큰을 노출시킴:

<?php
$token = "xoxb-your-token-here"; // 이렇게 하면 안 됨!
$channel = "#general";
$message = "Hello from Bot!";

$url = "https://slack.com/api/chat.postMessage";
$data = array(
  'token' => $token,
  'channel' => $channel,
  'text' => $message
);

$ch = curl_init($url);
curl_setopt_array($ch, array(
  CURLOPT_POST => 1,
  CURLOPT_POSTFIELDS => http_build_query($data),
  CURLOPT_RETURNTRANSFER => 1
));
$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

문제점: 토큰을 PHP 파일에 직접 적으면 git에 커밋될 위험이 있고, 소스코드 유출 시 누군가 이 토큰으로 Bot을 악용할 수 있다.

✓ 올바른 코드 - 환경변수로 토큰 관리:

<?php
// 환경변수에서 토큰 가져오기 (또는 .env 파일)
$token = getenv('SLACK_BOT_TOKEN');
if (!$token) {
  die('SLACK_BOT_TOKEN 환경변수가 설정되지 않았습니다.');
}

function sendSlackMessage($channel, $message, $token) {
  $url = "https://slack.com/api/chat.postMessage";
  
  $ch = curl_init($url);
  curl_setopt_array($ch, array(
    CURLOPT_POST => 1,
    CURLOPT_HTTPHEADER => array(
      "Authorization: Bearer $token",
      "Content-Type: application/json"
    ),
    CURLOPT_POSTFIELDS => json_encode(array(
      'channel' => $channel,
      'text' => $message
    )),
    CURLOPT_RETURNTRANSFER => 1
  ));
  
  $response = curl_exec($ch);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  
  $result = json_decode($response, true);
  
  if (!$result['ok']) {
    error_log('Slack API Error: ' . $result['error']);
    return false;
  }
  
  return true;
}

// 사용 예
$channel = "#general";
$message = "안녕! 이건 Bot이 보낸 메시지야!";

if (sendSlackMessage($channel, $message, $token)) {
  echo "메시지 전송 성공!";
} else {
  echo "메시지 전송 실패";
}
?>

핵심 개선사항:

- 토큰을 getenv()로 환경변수에서 가져옴 (소스에 노출 안 됨)
- Authorization 헤더로 토큰 전달 (더 안전한 방식)
- JSON으로 요청 (일관된 포맷)
- 응답 코드 확인 후 에러 로깅 (디버깅 용이)

 

4단계: 서식이 있는 Rich Message 보내기

단순 텍스트보다는 색상, 버튼, 필드가 있는 메시지(Block Kit)를 보내는 게 훨씬 보기 좋다. 예를 들어 배포 알림, 에러 로그, 승인 요청 등을 시각적으로 표시할 수 있다.

✗ 잘못된 방식 - 평문 텍스트만 사용:

// 이렇게 하면 읽기 어려움
$message = "배포 완료: server-v1.2.3, 시간: 2024-01-15 14:30, 상태: 성공";
sendSlackMessage($channel, $message, $token);

✓ 올바른 방식 - Block Kit 사용:

<?php
function sendSlackDeployNotification($channel, $app_name, $version, $status, $token) {
  $url = "https://slack.com/api/chat.postMessage";
  
  // 상태에 따라 색상 결정
  $color = ($status === 'success') ? '#36a64f' : '#ff0000';
  
  $blocks = array(
    array(
      'type' => 'header',
      'text' => array(
        'type' => 'plain_text',
        'text' => '🚀 배포 알림'
      )
    ),
    array(
      'type' => 'section',
      'fields' => array(
        array(
          'type' => 'mrkdwn',
          'text' => "*애플리케이션:*n{$app_name}"
        ),
        array(
          'type' => 'mrkdwn',
          'text' => "*버전:*n{$version}"
        ),
        array(
          'type' => 'mrkdwn',
          'text' => "*상태:*n{$status}"
        ),
        array(
          'type' => 'mrkdwn',
          'text' => "*시간:*n" . date('Y-m-d H:i:s')
        )
      )
    ),
    array(
      'type' => 'divider'
    ),
    array(
      'type' => 'section',
      'text' => array(
        'type' => 'mrkdwn',
        'text' => "상세 정보는 에서 확인하세요."
      )
    )
  );
  
  $ch = curl_init($url);
  curl_setopt_array($ch, array(
    CURLOPT_POST => 1,
    CURLOPT_HTTPHEADER => array(
      "Authorization: Bearer $token",
      "Content-Type: application/json"
    ),
    CURLOPT_POSTFIELDS => json_encode(array(
      'channel' => $channel,
      'blocks' => $blocks
    )),
    CURLOPT_RETURNTRANSFER => 1
  ));
  
  $response = curl_exec($ch);
  curl_close($ch);
  
  $result = json_decode($response, true);
  return $result['ok'];
}

// 사용 예
sendSlackDeployNotification('#dev-alerts', 'api-server', 'v1.2.3', 'success', $token);
?>

출력 결과: Slack에서 헤더, 구조화된 필드(2열), 구분선, 링크가 포함된 보기 좋은 메시지가 표시된다.

 

5단계: 인터랙티브 버튼이 있는 메시지

메시지에 버튼을 달아서 사용자가 클릭했을 때 특정 액션을 실행하게 할 수 있다. 예를 들어 "승인"/"거절" 버튼이 있는 배포 요청 메시지 같은 경우다.

인터랙티브 메시지를 보내는 PHP 코드:

<?php
function sendSlackApprovalMessage($channel, $request_id, $deploy_info, $token) {
  $url = "https://slack.com/api/chat.postMessage";
  
  $blocks = array(
    array(
      'type' => 'section',
      'text' => array(
        'type' => 'mrkdwn',
        'text' => "*배포 승인 요청*n앱: {$deploy_info['app']}n버전: {$deploy_info['version']}n요청자: {$deploy_info['requester']}"
      )
    ),
    array(
      'type' => 'actions',
      'elements' => array(
        array(
          'type' => 'button',
          'text' => array(
            'type' => 'plain_text',
            'text' => '✅ 승인'
          ),
          'value' => $request_id,
          'action_id' => 'approve_deploy',
          'style' => 'primary'
        ),
        array(
          'type' => 'button',
          'text' => array(
            'type' => 'plain_text',
            'text' => '❌ 거절'
          ),
          'value' => $request_id,
          'action_id' => 'reject_deploy',
          'style' => 'danger'
        )
      )
    )
  );
  
  $ch = curl_init($url);
  curl_setopt_array($ch, array(
    CURLOPT_POST => 1,
    CURLOPT_HTTPHEADER => array(
      "Authorization: Bearer $token",
      "Content-Type: application/json"
    ),
    CURLOPT_POSTFIELDS => json_encode(array(
      'channel' => $channel,
      'blocks' => $blocks
    )),
    CURLOPT_RETURNTRANSFER => 1
  ));
  
  $response = curl_exec($ch);
  curl_close($ch);
  
  $result = json_decode($response, true);
  return $result['ok'];
}

// 사용 예
sendSlackApprovalMessage('#deploy-approval', 'req-12345', array(
  'app' => 'api-server',
  'version' => 'v2.0.0',
  'requester' => 'john@company.com'
), $token);
?>

사용자가 버튼을 클릭하면 Slack이 webhook으로 우리 서버에 알림을 보낸다. 그 webhook을 받아서 처리하려면 별도 setup이 필요하다(Slack App 설정에서 "Interactivity" 활성화, webhook URL 등록).

 

6단계: 주의사항과 흔한 실수

✗ 실수 1: 토큰을 하드코딩

$token = "xoxb-1234567890-1234567890-abcdefg"; // 절대 금지!
// 이 코드가 github에 푸시되면 누구나 토큰을 볼 수 있음

✓ 올바른 방법: 환경변수나 .env 파일 사용

// .env 파일
SLACK_BOT_TOKEN=xoxb-...

// PHP 코드
require 'vendor/autoload.php';
$dotenv = DotenvDotenv::createImmutable(__DIR__);
$dotenv->load();
$token = $_ENV['SLACK_BOT_TOKEN'];

✗ 실수 2: 채널명에 #을 잘못 사용

// 채널 ID가 있으면 ID 사용이 더 정확함
sendSlackMessage('C1234567', $message, $token); // ✓
sendSlackMessage('#general', $message, $token);  // △ 작동하지만 이름으로는 고유성 보장 안 됨

✗ 실수 3: API 응답을 무시

// 응답을 확인하지 않으면 실패 원인을 모름
$response = curl_exec($ch);
// 응답을 확인해야 함
$result = json_decode($response, true);
if (!$result['ok']) {
  error_log('Slack API Error: ' . $result['error']);
}

✗ 실수 4: 너무 자주 메시지 보내기

Slack API에는 Rate Limit이 있다(초당 몇 요청). 대량 메시지를 보낼 때는 지연을 주거나 배치 처리를 해야 한다.

// 나쁜 방식: 바로 연속 전송
foreach ($alerts as $alert) {
  sendSlackMessage($channel, $alert, $token);
}

// 좋은 방식: 지연 추가
foreach ($alerts as $alert) {
  sendSlackMessage($channel, $alert, $token);
  sleep(1); // 1초 대기 (Rate Limit 회피)
}

 

7단계: 실전 예제 - 에러 로그 자동 알림

실제로 많이 쓰는 사례: 서버 에러가 발생하면 자동으로 Slack의 #error-alerts 채널에 알림을 보낸다.

<?php
class SlackErrorNotifier {
  private $token;
  private $channel;
  
  public function __construct($token, $channel = '#error-alerts') {
    $this->token = $token;
    $this->channel = $channel;
  }
  
  public function notifyError($error_message, $file, $line, $context = array()) {
    $url = "https://slack.com/api/chat.postMessage";
    
    $blocks = array(
      array(
        'type' => 'section',
        'text' => array(
          'type' => 'mrkdwn',
          'text' => "🚨 *에러 발생!*n`{$error_message}`"
        )
      ),
      array(
        'type' => 'section',
        'fields' => array(
          array(
            'type' => 'mrkdwn',
            'text' => "*파일:*n`{$file}`"
          ),
          array(
            'type' => 'mrkdwn',
            'text' => "*줄:*n{$line}"
          ),
          array(
            'type' => 'mrkdwn',
            'text' => "*시간:*n" . date('Y-m-d H:i:s')
          ),
          array(
            'type' => 'mrkdwn',
            'text' => "*서버:*n" . gethostname()
          )
        )
      )
    );
    
    if (!empty($context)) {
      $blocks[] = array(
        'type' => 'section',
        'text' => array(
          'type' => 'mrkdwn',
          'text' => "*컨텍스트:*n" . json_encode($context, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        )
      );
    }
    
    $ch = curl_init($url);
    curl_setopt_array($ch, array(
      CURLOPT_POST => 1,
      CURLOPT_HTTPHEADER => array(
        "Authorization: Bearer {$this->token}",
        "Content-Type: application/json"
      ),
      CURLOPT_POSTFIELDS => json_encode(array(
        'channel' => $this->channel,
        'blocks' => $blocks
      )),
      CURLOPT_RETURNTRANSFER => 1,
      CURLOPT_TIMEOUT => 5
    ));
    
    curl_exec($ch);
    curl_close($ch);
  }
}

// 사용 예
set_error_handler(function($errno, $errstr, $errfile, $errline) {
  $notifier = new SlackErrorNotifier(getenv('SLACK_BOT_TOKEN'));
  $notifier->notifyError(
    $errstr,
    $errfile,
    $errline,
    array(
      'user_id' => $_SESSION['user_id'] ?? 'unknown',
      'request_uri' => $_SERVER['REQUEST_URI'] ?? ''
    )
  );
  return false; // 기본 에러 핸들링도 계속 실행
});

// 에러 발생 시 자동으로 Slack에 알림
trigger_error('Database connection failed', E_USER_ERROR);
?>

이렇게 하면 개발팀이 중요한 에러를 실시간으로 Slack에서 받을 수 있다.

 

마무리

Slack Bot API는 단순해 보이지만 제대로 활용하면 팀의 커뮤니케이션과 모니터링을 획기적으로 개선할 수 있다. 토큰 관리, 에러 핸들링, Rate Limit 같은 작은 것들이 모여서 안정적인 자동화 시스템을 만든다는 점을 잊지 말자. 이 글의 실전 예제(에러 알림)를 참고해 자신의 프로젝트에 적용하면, 운영 중인 서비스에서 문제를 훨씬 빠르게 발견하고 대응할 수 있을 것이다.