着信SMS(MO)
受信SMSを受け取るには、番号インベントリから1つ以上の番号を取得し、それらをAPIキーに割り当てる必要があります。各APIキーには、受信メッセージを受け取るための複数の番号を関連付けることができます。
アカウントに割り当てられた番号の1つに送信されたSMSを受信すると、着信メッセージがWebhookアドレスに投稿されます。 このWebhookアドレスは、番号一覧から選択され、自分のアカウントに割り当てられた番号の設定として、カスタマーポータルで設定できます。
着信メッセージのWebhookは、"HTTP 200 OK"応答で確認応答する必要があります。 着信メッセージがWebhookアドレスに接続できない場合、または"HTTP 200 OK"以外の応答を受信した場合、メッセージはキューに入れられ、最大24時間再試行されてから、破棄されます。
Webhook呼び出しは、リクエスト本文にJSON形式を含むPOSTとして送信されます。
エンドポイント
Webhookコールは、JSONボディを含むHTTP POSTリクエストとして送信されます。
POST {Rakuten CPaaSに登録したWebhook URL、またはリクエスト内の「custom_callback_url」として指定されたWebhook URL}
リクエストパラメータ
WebhookのPOSTボディに含まれるJSONフィールドの一覧。
| パラメーター | 要否 | 詳細/値 |
|---|---|---|
| message_id | 必須 | SMS送信APIリクエストで返されたメッセージID |
| sender_address | Y | 送信元の電話番号 |
| destination_address | Y | お客様のアカウントに割り当てられた宛先の電話番号 |
| content_type | 必須 | エンコード種別:text(GSM-7)、unicode(UTF-16) |
| udh | 任意 | UDH(ユーザーデータヘッダー)フィールドの16進数表現。連結メッセージや特殊エンコードのメッセージに含まれます。未使用の場合は空文字列。 |
| message_body | 必須 | 受信したSMSのテキスト内容 |
ペイロード例
Webhookエンドポイントで受信するJSONボディの例です。
{
"message_id": "…submit sms APIリクエストで返却されたメッセージID…",
"sender_address": "…送信者アドレス…",
"destination_address": "…宛先の電話番号…",
"content_type": "text、unicode、またはbinary",
"udh": "…メッセージ内に存在する場合のudhフィールドの16進表現…",
"message_body": "配信されるメッセージの内容"
}
サンプルペイロード
{
"message_id": "msg-00123abc456def789",
"sender_address": "819012345678",
"destination_address": "815011112222",
"content_type": "unicode",
"udh": "",
"message_body": "Thank you for contacting us. Your inquiry number is 12345."
}
- cURL
- JavaScript
- Python
- PHP
- Java
ローカル開発環境でWebhookエンドポイントを検証するためのコマンド。
curl -X POST http://localhost:3000/mo-webhook \
-H "Content-Type: application/json" \
-d '{
"message_id": "test-msg-001",
"sender_address": "819012345678",
"destination_address": "815011112222",
"content_type": "text",
"udh": "",
"message_body": "This is a test message"
}'
const express = require('express');
const app = express();
app.use(express.json());
app.post('/mo-webhook', (req, res) => {
const body = req.body;
if (!body || typeof body !== 'object' || Array.isArray(body)) {
return res.status(400).json({ error: 'Invalid or missing JSON body' });
}
const {
message_id = '',
sender_address = '',
destination_address = '',
content_type = '',
udh = '',
message_body = ''
} = body;
console.log(`[MO received] from=${sender_address} to=${destination_address}`);
console.log(` message_id : ${message_id}`);
console.log(` content_type : ${content_type}`);
console.log(` udh : ${udh || '(none)'}`);
console.log(` message_body : ${message_body}`);
return res.status(200).json({ status: 'received' });
});
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
return res.status(400).json({ error: 'Invalid JSON body' });
}
return res.status(500).json({ error: 'Internal server error' });
});
app.listen(3000, () => console.log('Webhook server listening on port 3000'));;
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/mo-webhook', methods=['POST'])
def mo_webhook():
data = request.get_json(silent=True)
# Guard: reject requests with no JSON body
if data is None:
return jsonify({'error': 'Invalid or missing JSON body'}), 400
message_id = data.get('message_id', '')
sender_address = data.get('sender_address', '')
destination_address = data.get('destination_address', '')
content_type = data.get('content_type', '')
udh = data.get('udh', '')
message_body = data.get('message_body', '')
print(f'[MO received] from={sender_address} to={destination_address}')
print(f' message_id : {message_id}')
print(f' content_type : {content_type}')
print(f' udh : {udh or "(none)"}')
print(f' message_body : {message_body}')
# Add your business logic here
# Rakuten CPaaS expects HTTP 200 OK
return jsonify({'status': 'received'}), 200
if __name__ == '__main__':
# Development server only — use gunicorn for production:
# gunicorn -w 4 mo_webhook:app
app.run(port=3000)
<?php
$json = file_get_contents('php://input');
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) {
header('Content-Type: application/json');
http_response_code(400);
echo json_encode(['error' => 'Invalid or missing JSON body']);
exit;
}
$message_id = $data['message_id'] ?? '';
$sender_address = $data['sender_address'] ?? '';
$destination_address = $data['destination_address'] ?? '';
$content_type = $data['content_type'] ?? '';
$udh = $data['udh'] ?? '';
$message_body = $data['message_body'] ?? '';
error_log("[MO received] from={$sender_address} to={$destination_address}");
header('Content-Type: application/json');
http_response_code(200);
echo json_encode(['status' => 'received']);
// Required dependencies (Maven):
// spring-boot-starter-web
// jackson-databind (included transitively with spring-boot-starter-web)
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class MoWebhookController {
@PostMapping("/mo-webhook")
public ResponseEntity<Map<String, String>> handleMo(
@RequestBody Map<String, String> payload) {
String messageId = payload.getOrDefault("message_id", "");
String senderAddress = payload.getOrDefault("sender_address", "");
String destinationAddress = payload.getOrDefault("destination_address", "");
String contentType = payload.getOrDefault("content_type", "");
String udh = payload.getOrDefault("udh", "");
String messageBody = payload.getOrDefault("message_body", "");
System.out.printf("[MO received] from=%s to=%s%n", senderAddress, destinationAddress);
System.out.printf(" message_id : %s%n", messageId);
System.out.printf(" content_type : %s%n", contentType);
System.out.printf(" udh : %s%n", udh.isEmpty() ? "(none)" : udh);
System.out.printf(" message_body : %s%n", messageBody);
// Add your business logic here
// Rakuten CPaaS expects HTTP 200 OK
return ResponseEntity.ok(Map.of("status", "received"));
}
}
実装上の注意事項
| 項目 | 詳細 |
|---|---|
| レスポンス要件 | HTTP 200 OK を返す必要があります。他のレスポンスコードはリトライを引き起こします。 |
| リトライポリシー | 接続失敗または200以外のレスポンスの場合、最大24時間リトライされた後、自動的に破棄されます。 |
| 冪等性 | リトライにより同じ message_id が複数回届く場合があります。message_id を使用した重複排除の実装を強く推奨します。 |
| content_type | content_type が unicode の場合、ボディはUTF-16エンコードです。日本語文字や絵文字を含むSMSは通常 unicode になります。 |
| 連結SMS | 長いメッセージは分割して配信されます。udh フィールドには連結参照、総パーツ数、シーケンス番号が含まれます。必要に応じて再組み立てロジックを実装してください。 |
| HTTPS必須 | 本番環境では常にWebhook URLにHTTPSを使用してください。 |