콘텐츠로 이동

메시지 상태 확인

상태 확인 엔드포인트를 사용하여 메시지의 배달 상태를 추적하세요.

엔드포인트

GET /bat/message/{messageId}

요청

URL 매개변수

매개변수 유형 필수 설명
메시지 ID 문자열 보내기 응답의 고유 메시지 식별자

인증

세 가지 인증 방법 중 하나를 사용하십시오.

curl -X GET https://restapi.smsbat.com/bat/message/abc123def456 \
  -H "X-Authorization-Key: your-api-key"
curl -X GET https://restapi.smsbat.com/bat/message/abc123def456 \
  -u "username:password"
curl -X GET https://restapi.smsbat.com/bat/message/abc123def456 \
  -u "@:your-api-key"

응답

기본 응답

{
  "messagelistId": 123456,
  "messageId": "abc123def456",
  "deliverystatus": "delivered",
  "partscount": 1,
  "cost": 0.05
}

응답 필드

필드 유형 설명
messagelistId 정수 배치 식별자
메시지 ID 문자열 고유한 메시지 식별자
배송 상태 문자열 배송현황
'부품수' 정수 메시지 부분 수
'비용' 번호 통화 단위의 메시지 비용

확장 응답(대체 포함)

대체가 구성되면 응답에 추가 필드가 포함됩니다.

{
  "messagelistId": 123456,
  "messageId": "abc123def456",
  "deliverystatus": "delivered",
  "partscount": 1,
  "cost": 0.05,
  "fallbacks": [
    {
      "type": "sms",
      "status": "not_used"
    }
  ],
  "extendedStatuses": {
    "viber": "delivered",
    "sms": "not_used"
  },
  "rate": 0.05,
  "rateAmount": 0.05,
  "rateCurrency": "USD",
  "billAmount": 0.05,
  "billCurrency": "USD"
}

배송 상태 값

상태 설명
예정 전송 대기 중
'처리' 현재 전송 중
'배달됨' 성공적으로 전달됨
'배달할 수 없음' 배달 실패, 메시지 거부
영구 오류 지속적인 오류로 인해 대기열에서 제거됨

상태 수명주기

graph LR
    A[scheduled] --> B[processing]
    B --> C[delivered]
    B --> D[undeliverable]
    B --> E[permanenterror]

예정됨

메시지가 승인되어 배달 대기 중입니다.

{
  "deliverystatus": "scheduled",
  "partscount": 1
}

처리 중

메시지가 현재 수신자에게 전송되고 있습니다:

{
  "deliverystatus": "processing",
  "partscount": 1
}

배달됨

메시지가 수신자에게 성공적으로 전달되었습니다.

{
  "deliverystatus": "delivered",
  "partscount": 1,
  "cost": 0.05
}

배송 불가

메시지를 전달할 수 없습니다(잘못된 번호, 네트워크 오류):

{
  "deliverystatus": "undeliverable",
  "partscount": 1,
  "cost": 0.00
}

영구 오류

지속적인 전송 문제로 인해 대기열에서 메시지가 제거되었습니다.

{
  "deliverystatus": "permanenterror",
  "partscount": 1,
  "cost": 0.00
}

여러 메시지 확인

애플리케이션에서 여러 메시지의 상태를 확인하세요.

// JavaScript example
async function checkMessageStatuses(messageIds) {
  const statuses = await Promise.all(
    messageIds.map(async (messageId) => {
      const response = await fetch(
        `https://restapi.smsbat.com/bat/message/${messageId}`,
        {
          headers: {
            'X-Authorization-Key': 'your-api-key'
          }
        }
      );
      return response.json();
    })
  );

  return statuses;
}

// Usage
const messageIds = ['abc123', 'def456', 'ghi789'];
const statuses = await checkMessageStatuses(messageIds);

statuses.forEach(status => {
  console.log(`Message ${status.messageId}: ${status.deliverystatus}`);
});

상태 업데이트 폴링

상태 엔드포인트를 폴링하여 전달을 추적합니다.

// Poll every 5 seconds until delivered
async function waitForDelivery(messageId, maxAttempts = 12) {
  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `https://restapi.smsbat.com/bat/message/${messageId}`,
      {
        headers: { 'X-Authorization-Key': 'your-api-key' }
      }
    );

    const status = await response.json();

    if (status.deliverystatus === 'delivered') {
      return { success: true, status };
    }

    if (status.deliverystatus === 'undeliverable' ||
        status.deliverystatus === 'permanenterror') {
      return { success: false, status };
    }

    // Wait 5 seconds before next check
    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  // Timeout after 60 seconds
  return { success: false, timeout: true };
}

웹훅 대안

폴링 대신 실시간 상태 업데이트를 위해 웹후크를 사용하세요.

POST https://your-server.com/webhook
{
  "messageId": "abc123def456",
  "deliverystatus": "delivered",
  "timestamp": "2025-01-23T10:30:00Z",
  "cost": 0.05
}

웹훅 URL을 구성하려면 계정 관리자에게 문의하세요.

구현 예

파이썬

import requests
import time

def check_status(message_id, api_key):
    url = f"https://restapi.smsbat.com/bat/message/{message_id}"
    headers = {"X-Authorization-Key": api_key}

    response = requests.get(url, headers=headers)
    return response.json()

def wait_for_delivery(message_id, api_key, timeout=60):
    """Poll until delivered or timeout"""
    start_time = time.time()

    while time.time() - start_time < timeout:
        status = check_status(message_id, api_key)

        if status['deliverystatus'] == 'delivered':
            return {'success': True, 'status': status}

        if status['deliverystatus'] in ['undeliverable', 'permanenterror']:
            return {'success': False, 'status': status}

        time.sleep(5)

    return {'success': False, 'timeout': True}

# Usage
message_id = "abc123def456"
result = wait_for_delivery(message_id, "your-api-key")

if result['success']:
    print(f"Message delivered! Cost: {result['status']['cost']}")
else:
    print("Message delivery failed or timeout")

PHP

<?php

function checkStatus($messageId, $apiKey) {
    $url = "https://restapi.smsbat.com/bat/message/" . $messageId;

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "X-Authorization-Key: " . $apiKey
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

function waitForDelivery($messageId, $apiKey, $timeout = 60) {
    $startTime = time();

    while (time() - $startTime < $timeout) {
        $status = checkStatus($messageId, $apiKey);

        if ($status['deliverystatus'] === 'delivered') {
            return ['success' => true, 'status' => $status];
        }

        if (in_array($status['deliverystatus'],
                    ['undeliverable', 'permanenterror'])) {
            return ['success' => false, 'status' => $status];
        }

        sleep(5);
    }

    return ['success' => false, 'timeout' => true];
}

// Usage
$messageId = "abc123def456";
$result = waitForDelivery($messageId, "your-api-key");

if ($result['success']) {
    echo "Message delivered! Cost: " . $result['status']['cost'];
} else {
    echo "Message delivery failed or timeout";
}

Node.js

const axios = require('axios');

async function checkStatus(messageId, apiKey) {
  const response = await axios.get(
    `https://restapi.smsbat.com/bat/message/${messageId}`,
    {
      headers: { 'X-Authorization-Key': apiKey }
    }
  );

  return response.data;
}

async function waitForDelivery(messageId, apiKey, timeout = 60000) {
  const startTime = Date.now();

  while (Date.now() - startTime < timeout) {
    const status = await checkStatus(messageId, apiKey);

    if (status.deliverystatus === 'delivered') {
      return { success: true, status };
    }

    if (['undeliverable', 'permanenterror'].includes(
      status.deliverystatus
    )) {
      return { success: false, status };
    }

    // Wait 5 seconds
    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  return { success: false, timeout: true };
}

// Usage
const messageId = 'abc123def456';
const result = await waitForDelivery(messageId, 'your-api-key');

if (result.success) {
  console.log(`Message delivered! Cost: ${result.status.cost}`);
} else {
  console.log('Message delivery failed or timeout');
}

모범 사례

폴링 빈도

  • ✅ 5~10초마다 폴링
  • ✅ 지수 백오프 구현
  • ✅ 합리적인 시간 초과 설정(60-120초)
  • ❌ 초당 한 번 이상 폴링하지 마세요.
  • ❌ 무한정 여론조사를 하지 마세요

오류 처리

async function checkStatusWithRetry(messageId, apiKey, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(
        `https://restapi.smsbat.com/bat/message/${messageId}`,
        {
          headers: { 'X-Authorization-Key': apiKey }
        }
      );

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      if (i === retries - 1) throw error;

      // Wait before retry (exponential backoff)
      await new Promise(resolve =>
        setTimeout(resolve, Math.pow(2, i) * 1000)
      );
    }
  }
}

캐싱

API 호출을 줄이기 위한 캐시 상태 결과:

const statusCache = new Map();

async function getCachedStatus(messageId, apiKey, cacheTTL = 30000) {
  const cached = statusCache.get(messageId);

  if (cached && Date.now() - cached.timestamp < cacheTTL) {
    return cached.status;
  }

  const status = await checkStatus(messageId, apiKey);

  statusCache.set(messageId, {
    status,
    timestamp: Date.now()
  });

  return status;
}

일괄 처리

많은 메시지를 확인할 때 일괄 요청은 다음과 같습니다.

async function checkBatchStatus(messageIds, apiKey, batchSize = 10) {
  const results = [];

  for (let i = 0; i < messageIds.length; i += batchSize) {
    const batch = messageIds.slice(i, i + batchSize);
    const batchResults = await Promise.all(
      batch.map(id => checkStatus(id, apiKey))
    );
    results.push(...batchResults);

    // Rate limiting
    if (i + batchSize < messageIds.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  return results;
}

사용 사례

주문 확인

주문 확인 메시지 전달 추적:

const orderMessage = await sendMessage({
  to: customer.phone,
  text: `Order #${orderId} confirmed`
});

// Wait for delivery
const result = await waitForDelivery(orderMessage.messageId, apiKey);

if (result.success) {
  await updateOrder(orderId, { notificationSent: true });
} else {
  await scheduleRetry(orderId);
}

2단계 인증

시간 초과 전에 OTP 전달을 확인하십시오.

const otpMessage = await sendOTP(userPhone, otpCode);

// Poll for delivery
const delivered = await waitForDelivery(
  otpMessage.messageId,
  apiKey,
  30 // 30 second timeout
);

if (!delivered.success) {
  // Send via alternative channel
  await sendEmailOTP(userEmail, otpCode);
}

마케팅 캠페인

캠페인 메시지 전달률 추적:

const messageIds = await sendCampaign(recipientList);

// Check all statuses after 5 minutes
setTimeout(async () => {
  const statuses = await checkBatchStatus(messageIds, apiKey);

  const delivered = statuses.filter(s =>
    s.deliverystatus === 'delivered'
  ).length;

  console.log(`Delivery rate: ${delivered / statuses.length * 100}%`);
}, 5 * 60 * 1000);

다음 단계