노티페이는 입금 SMS를 파싱해 사용자가 지정한 엔드포인트로 JSON을 POST합니다.
단순한 웹훅 구조이므로 어떤 서버 환경에서도 5분 안에 연동할 수 있습니다.
Webhook URL 카드에 준비한 URL 입력 → 저장.
application/json; charset=utf-8
{
"deposit_datetime": "06/02 11:35",
"depositor_name": "홍길동",
"amount": "70000"
}
| 필드 | 타입 | 설명 | 예시 |
|---|---|---|---|
deposit_datetime |
string | 은행 SMS에 기재된 입금 일시 (은행마다 형식 다름) | "06/02 11:35" |
depositor_name |
string | 입금자명 (한글/영문 모두) | "홍길동" |
amount |
string | 입금 금액 — 콤마/원 표시 제거된 순수 숫자 문자열 | "70000" |
서버는 처리 결과를 JSON으로 반환해야 하며, HTTP 상태 코드 200 + body의 status 필드가 "success"일 때만 성공으로 간주합니다.
{
"status": "success",
"message": "Data received successfully."
}
{
"status": "error",
"message": "Missing required data."
}
{"status":"success"}가 아니거나 200 외 상태 코드면 앱이 자동으로 재시도합니다.
엔드포인트는 멱등(idempotent)해야 합니다 — 같은 데이터가 여러 번 도착해도 중복 처리되지 않도록 설계하세요.
webhook.site 접속 → "Your unique URL" 복사 → 앱에 붙여넣고 저장. 입금 SMS 받으면 그 사이트에서 JSON이 도착하는 것을 실시간으로 확인 가능합니다.
curl -X POST https://your-server.example.com/webhook \
-H "Content-Type: application/json" \
-d '{"deposit_datetime":"06/02 11:35","depositor_name":"홍길동","amount":"70000"}'
아래는 노티페이가 보낸 JSON을 받아서 처리하는 최소 예제입니다.
<?php
header('Content-Type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'POST only.']);
exit;
}
// JSON Body 파싱
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)
|| !isset($data['deposit_datetime'], $data['depositor_name'], $data['amount'])) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Missing required data.']);
exit;
}
// === 여기서 본인 비즈니스 로직 처리 ===
// $data['deposit_datetime'] : "06/02 11:35"
// $data['depositor_name'] : "홍길동"
// $data['amount'] : "70000" (string, 숫자만)
// 예: DB 저장, 슬랙 알림, ERP 연동 등
// ====================================
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'OK']);
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
const { deposit_datetime, depositor_name, amount } = req.body || {};
if (!deposit_datetime || !depositor_name || !amount) {
return res.status(400).json({ status: 'error', message: 'Missing required data.' });
}
// 비즈니스 로직 (예: DB 저장)
console.log(`입금: ${depositor_name} ${amount}원 @ ${deposit_datetime}`);
res.status(200).json({ status: 'success', message: 'OK' });
});
app.listen(3000, () => console.log('listening on 3000'));
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get('Content-Length', 0))
try:
data = json.loads(self.rfile.read(length).decode('utf-8'))
except json.JSONDecodeError:
self._reply(400, {'status': 'error', 'message': 'Invalid JSON.'})
return
required = ('deposit_datetime', 'depositor_name', 'amount')
if not all(k in data for k in required):
self._reply(400, {'status': 'error', 'message': 'Missing required data.'})
return
# 비즈니스 로직
print(f"입금: {data['depositor_name']} {data['amount']}원")
self._reply(200, {'status': 'success', 'message': 'OK'})
def _reply(self, code, body):
self.send_response(code)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(json.dumps(body).encode('utf-8'))
HTTPServer(('', 8000), Handler).serve_forever()
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.get_json(silent=True) or {}
if not all(k in data for k in ('deposit_datetime', 'depositor_name', 'amount')):
return jsonify(status='error', message='Missing required data.'), 400
# 비즈니스 로직
print(f"입금: {data['depositor_name']} {data['amount']}원")
return jsonify(status='success', message='OK'), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class WebhookController {
@PostMapping("/webhook")
public ResponseEntity<Map<String, String>> receive(@RequestBody Map<String, String> body) {
String dt = body.get("deposit_datetime");
String name = body.get("depositor_name");
String amt = body.get("amount");
if (dt == null || name == null || amt == null) {
return ResponseEntity.badRequest().body(Map.of(
"status", "error", "message", "Missing required data."
));
}
// 비즈니스 로직
System.out.printf("입금: %s %s원%n", name, amt);
return ResponseEntity.ok(Map.of("status", "success", "message", "OK"));
}
}
using Microsoft.AspNetCore.Mvc;
public class DepositPayload {
public string deposit_datetime { get; set; }
public string depositor_name { get; set; }
public string amount { get; set; }
}
[ApiController]
[Route("webhook")]
public class WebhookController : ControllerBase {
[HttpPost]
public IActionResult Receive([FromBody] DepositPayload p) {
if (string.IsNullOrEmpty(p?.deposit_datetime)
|| string.IsNullOrEmpty(p.depositor_name)
|| string.IsNullOrEmpty(p.amount))
return BadRequest(new { status = "error", message = "Missing required data." });
// 비즈니스 로직
Console.WriteLine($"입금: {p.depositor_name} {p.amount}원");
return Ok(new { status = "success", message = "OK" });
}
}
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Payload struct {
DepositDatetime string `json:"deposit_datetime"`
DepositorName string `json:"depositor_name"`
Amount string `json:"amount"`
}
type Resp struct {
Status string `json:"status"`
Message string `json:"message"`
}
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
json.NewEncoder(w).Encode(Resp{"error", "POST only."})
return
}
var p Payload
if err := json.NewDecoder(r.Body).Decode(&p); err != nil ||
p.DepositDatetime == "" || p.DepositorName == "" || p.Amount == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(Resp{"error", "Missing required data."})
return
}
// 비즈니스 로직
fmt.Printf("입금: %s %s원\n", p.DepositorName, p.Amount)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(Resp{"success", "OK"})
}
func main() {
http.HandleFunc("/webhook", handler)
http.ListenAndServe(":8080", nil)
}
require 'sinatra'
require 'json'
post '/webhook' do
content_type :json
data = JSON.parse(request.body.read) rescue {}
unless %w[deposit_datetime depositor_name amount].all? { |k| data.key?(k) }
status 400
return { status: 'error', message: 'Missing required data.' }.to_json
end
# 비즈니스 로직
puts "입금: #{data['depositor_name']} #{data['amount']}원"
status 200
{ status: 'success', message: 'OK' }.to_json
end
<%@ page contentType="application/json; charset=UTF-8" %>
<%@ page import="java.io.*, org.json.JSONObject" %>
<%
if (!"POST".equalsIgnoreCase(request.getMethod())) {
response.setStatus(405);
out.print(new JSONObject().put("status","error").put("message","POST only."));
return;
}
StringBuilder sb = new StringBuilder();
try (BufferedReader br = request.getReader()) {
String line; while ((line = br.readLine()) != null) sb.append(line);
}
JSONObject data = new JSONObject(sb.toString());
if (!data.has("deposit_datetime") || !data.has("depositor_name") || !data.has("amount")) {
response.setStatus(400);
out.print(new JSONObject().put("status","error").put("message","Missing required data."));
return;
}
// 비즈니스 로직
System.out.println("입금: " + data.getString("depositor_name") + " " + data.getString("amount") + "원");
response.setStatus(200);
out.print(new JSONObject().put("status","success").put("message","OK"));
%>
?token=abc123).depositor_name + amount + deposit_datetime를 해시로 만들어 중복 키로 사용하는 방법이 일반적입니다.
(int)$data['amount'], JavaScript parseInt(amount, 10) 식으로 변환하세요.
"06/02 11:35", 신한: "06/02 11:35:42".
앱은 SMS에 적힌 그대로 전달하며 ISO 8601 등으로 정규화하지 않습니다.
엄격한 datetime 포맷이 필요하면 수신측에서 파싱·재포맷하세요.