개발자 센터

BankFlow은 은행 입출금 알림을 통합 관리하고, 실시간 입금 자동매칭을 제공하는 SaaS 플랫폼입니다.

API를 통해 다음 기능을 이용할 수 있습니다:

인증

모든 API 요청에는 다음 헤더가 필요합니다:

Content-Type: application/json
X-API-Key: your-api-key
X-Store-Id: your-store-key  (선택, 주문 API 사용 시 필요)

API Key는 대시보드 > 설정 > API 키에서 생성할 수 있습니다.

X-Store-Id는 여러 사이트를 운영할 때 어떤 사이트의 요청인지 구분하기 위한 헤더입니다. 대시보드 > 상점 관리에서 상점을 등록하면 Store Key가 발급됩니다.

API Key는 회사별로 발급되며, 해당 회사의 데이터에만 접근할 수 있습니다. 회사 전체 키 하나로 여러 상점의 주문을 관리할 수 있고, 다른 서버에 둘 키는 상점 전용 API 키로 만들면 그 상점의 것만 다룹니다.

오류 처리

모든 응답은 JSON 형식이며, success 필드로 성공 여부를 판단합니다:

성공 응답

{
  "success": true,
  "message": "주문이 등록되었습니다.",
  "data": { ... }
}

실패 응답

{
  "success": false,
  "message": "필수 항목이 누락되었습니다: amount"
}
HTTP 코드의미
200성공
400잘못된 요청 (파라미터 오류)
401인증 실패 (API Key 오류)
403권한 없음
404리소스 없음
405허용되지 않는 메서드
409충돌 (중복 등)
500서버 오류

입출금 데이터 실시간 수신

계좌에 입출금이 발생하면 알림전달앱 → BankFlow → 등록된 Webhook URL로 데이터를 전송합니다.

설정 방법

  1. 대시보드 > 설정에서 Webhook URL과 Webhook Secret을 확인합니다.
  2. 알림전달앱에 Webhook URL을 등록합니다.
  3. 은행 앱에서 SMS 통지 서비스를 신청합니다.

수신 데이터 형식

알림전달앱에서 BankFlow로 전송하는 형식:

POST https://bankflow.co.kr/api/v1/webhook

인증 방식 (택 1)

방식설명
API 키헤더에 X-API-Key: your-api-key
시크릿Body에 "secret": "your-webhook-secret" 포함
알림전달앱처럼 헤더 설정이 어려운 경우 Body에 시크릿을 포함하면 됩니다.

요청 Body

{
  "message": "[입금] 홍길동 313,500원 1005-204-572***계좌 잔액 7,566,003원 04/17 16:29:16",
  "source": "macrodroid",
  "secret": "your-webhook-secret"
}

또는 상세 형식:

{
  "app": "알림전달앱이름",
  "title": "우리은행",
  "message": "[입금] 홍길동 313,500원 1005-204-572***계좌 잔액 7,566,003원 04/17 16:29:16",
  "timestamp": "2024-04-17 16:29:16",
  "secret": "your-webhook-secret"
}
중복 알림: 같은 입금 알림이 두 번 들어오면(예: 문자와 푸시를 둘 다 전달) 같은 계좌·종류·금액·상대방 이름에 거래 시각 차이 3분 이내인 거래가 이미 있으면 두 번째는 저장하지 않습니다(잔액이 둘 다 있고 서로 다르면 다른 거래로 봅니다). 이때도 응답은 성공이며 data.duplicate 가 true 입니다. 다시 보낼 필요가 없습니다.

주문 등록

무통장입금 주문을 등록합니다. 해당 금액+입금자명으로 입금이 발생하면 자동으로 매칭됩니다.

POST https://bankflow.co.kr/api/v1/order

Request Body

필드타입필수설명
order_refstringO쇼핑몰 주문번호 (고유)
amountintegerO주문 금액 (원)
depositor_namestringO예상 입금자명
buyer_namestring주문자명 (입금자와 다를 경우)
bank_account_idinteger특정 계좌만 매칭 (미지정 시 전체)
callback_urlstring매칭 완료 시 결과 전송할 URL
expires_hoursinteger매칭 대기 시간 (기본 336=14일)
metaobject추가 데이터 (콜백 시 함께 전달)

요청 예시

{
  "order_ref": "ORD-20240417-001",
  "amount": 50000,
  "depositor_name": "홍길동",
  "callback_url": "https://myshop.com/api/payment-confirm",
  "meta": {
    "product": "프리미엄 플랜",
    "user_id": 1234
  }
}

응답 예시

{
  "success": true,
  "message": "주문이 등록되었습니다.",
  "data": {
    "order_id": 1,
    "order_ref": "ORD-20240417-001",
    "status": "pending",
    "matched": false
  }
}
매칭 조건: 입금자명과 금액이 정확히 일치하는 pending 주문이 1건일 때 자동매칭됩니다. 일치하는 주문이 0건이면 무시, 2건 이상이면 관리자에게 알림이 발송됩니다. 관리자가 등록한 입금자 별칭(주문에 적힌 이름 ↔ 실제 입금자명)이 있으면 그 이름의 주문도 후보가 됩니다(금액 조건은 그대로).

등록하자마자 매칭되는 경우 (역방향 매칭)

입금이 주문 등록보다 먼저 들어올 수 있습니다. 주문을 등록할 때 최근 일정 시간 안에 들어온, 아직 어느 주문에도 연결되지 않은 입금 중 금액과 입금자명(또는 별칭)이 맞는 것이 정확히 1건이면 바로 매칭하고 응답에 표시합니다. 2건 이상이면 매칭하지 않고 관리자 확인으로 넘깁니다.

범위는 기본 2시간이고, 관리자 화면(주문 관리 › 매칭 설정)에서 역방향 매칭을 끄거나 1~24시간으로 조절할 수 있습니다. 끄면 등록 응답은 항상 "matched": false 이고, 입금이 들어올 때의 매칭만 동작합니다. 범위를 길게 잡을수록 이미 손으로 처리한 입금이 새 주문에 다시 연결될 위험이 커집니다.

{
  "success": true,
  "message": "주문이 등록되었고, 먼저 들어온 입금과 바로 매칭되었습니다.",
  "data": {
    "order_id": 1,
    "order_ref": "ORD-20240417-001",
    "status": "pending",
    "matched": true,
    "match_type": "reverse",
    "matched_at": "2024-04-17 16:30:02"
  }
}
필드설명
matched등록과 동시에 매칭됐으면 true. status 는 등록 시점 값(pending) 그대로입니다.
match_type바로 매칭된 경우 reverse
match_held맞는 입금이 여러 건이라 보류한 경우 true (관리자가 수동매칭)
바로 매칭된 경우에도 callback_url 로 order.matched 콜백이 갑니다. 콜백은 이 응답을 돌려준 뒤에 보내므로, 응답을 받기 전에 주문을 저장해 두세요. 이 경로의 콜백은 대기 재시도 없이 한 번 보내며, 실패하면 관리자가 재전송합니다(이벤트 ID · 재전송).

주문 매칭제외

특정 주문을 매칭 대상에서 제외합니다.

POST https://bankflow.co.kr/api/v1/order-exclude

Request Body

{
  "order_ref": "ORD-20240417-001"
}
// 또는
{
  "order_id": 1
}

주문 조회

등록된 주문 목록을 조회합니다.

GET https://bankflow.co.kr/api/v1/orders?status=pending&page=1&per_page=30

Query Parameters

파라미터설명
statuspending, matched, excluded, expired, cancelled (선택)
page페이지 번호 (기본 1)
per_page페이지당 건수 (기본 30, 최대 100)

매칭 완료 Webhook

주문이 입금과 매칭되면 등록된 callback_url로 다음 데이터가 전송됩니다:

WEBHOOK callback_url (고객사 서버)

{
  "event": "order.matched",
  "event_id": "evt_8fK2mQ9xLr4TzA7bN1cV5wYd",
  "order_id": 1,
  "order_ref": "ORD-20240417-001",
  "amount": 50000,
  "depositor_name": "홍길동",
  "transaction_id": 123,
  "matched_at": "2024-04-17 16:29:16",
  "balance_after": 7566003,
  "match_type": "auto",
  "meta": {
    "product": "프리미엄 플랜",
    "user_id": 1234
  }
}
필드설명
event_id이벤트 고유 ID. 자동 재시도·관리자 재전송 때도 같은 값입니다(이벤트 ID · 재전송).
match_typeauto(입금이 들어올 때 매칭), reverse(주문 등록 때 먼저 들어온 입금과 매칭), manual(관리자 수동매칭)

응답 규격

콜백을 정상적으로 수신했으면 아래와 같이 응답해야 합니다. 미응답 또는 오류 시 최대 3회 재전송됩니다.

항목값
HTTP 상태코드200
Content-Typeapplication/json
Response Body{"status": "success"}
// PHP 예시
http_response_code(200);
header('Content-Type: application/json');
echo json_encode(['status' => 'success']);
재전송 정책: 최대 3회 시도 (즉시 → 30초 후 → 60초 후). 최종 실패 시 관리자에게 알림이 발송됩니다. {"status": "success"}가 아닌 응답은 모두 실패로 간주됩니다.

서명 검증

BankFlow가 보내는 콜백·웹훅에는 진짜 BankFlow 요청인지 확인할 수 있도록 서명 헤더가 붙습니다.

헤더값
X-BankFlow-Timestamp보낸 시각 (유닉스 초). 재전송마다 새로 만듭니다.
X-BankFlow-Signaturesha256= + HMAC-SHA256(Timestamp + "." + 받은 본문 그대로, 시크릿)의 hex

시크릿: 매칭 완료 콜백은 주문의 상점(Store) 시크릿, 알림 웹훅은 설정의 Webhook Secret입니다. 시크릿이 없는 상점은 서명 헤더 없이 전송됩니다. 주문 매칭 콜백 비밀값은 관리자 › 상점 관리에서 확인할 수 있습니다.

// PHP 검증 예시 — 본문은 json_decode 전에 받은 그대로 사용
$raw = file_get_contents('php://input');
$ts  = $_SERVER['HTTP_X_BANKFLOW_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_BANKFLOW_SIGNATURE'] ?? '';

$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (!ctype_digit($ts) || abs(time() - (int) $ts) > 300 || !hash_equals($expected, $sig)) {
    http_response_code(401);  // 5분 넘은 요청이나 서명 불일치는 거절
    exit;
}
$data = json_decode($raw, true);

이벤트 ID · 재전송

모든 콜백·웹훅(order.matched, transaction.alert, transaction.flagged)에는 이벤트 고유 ID가 붙습니다.

위치값
본문 event_idevt_ + 영숫자 24자 (JSON 형식일 때)
헤더 X-BankFlow-Event-Id본문과 같은 값 (메시지 형식 웹훅은 헤더에만)
헤더 X-BankFlow-Attempt몇 번째 시도인지 (재시도·재전송마다 1씩 늘어남)
같은 event_id 는 한 번만 처리하세요. 응답이 늦거나 끊기면 같은 이벤트가 다시 올 수 있습니다(자동 재시도, 관리자 재전송). 받은 event_id 를 저장해 두고 이미 처리한 값이면 처리하지 말고 {"status": "success"} 로 답하면 됩니다.

재전송: 끝내 실패한 이벤트는 관리자가 BankFlow 관리자 › Webhook 로그 › 발신 로그에서 「재전송」으로 다시 보낼 수 있습니다. 재전송은 event_id 와 본문 내용은 그대로, X-BankFlow-Timestamp·X-BankFlow-Signature 는 보내는 시각으로 새로 만들고, X-BankFlow-Attempt 는 이어서 늘어납니다. 이미 성공한 이벤트는 다시 보내지 않습니다.

상점 (Store)

여러 사이트를 운영하는 경우, 각 사이트를 상점(Store)으로 등록하여 독립적으로 관리할 수 있습니다.

상점별 분리 항목

항목설명
Store KeyAPI 요청 시 X-Store-Id 헤더에 사용
콜백 URL주문별 미지정 시 상점의 기본 URL 사용
연결 계좌이 상점의 입금을 특정 계좌에서만 매칭
주문 네임스페이스상점별로 order_ref 독립 관리 (다른 상점과 겹쳐도 OK)

사용 예시

// BlogMate에서 주문 등록
POST /api/v1/order
Headers:
  X-API-Key: bf_xxxxx
  X-Store-Id: blogmate

// Work ERP에서 주문 등록 (같은 API Key, 다른 Store)
POST /api/v1/order
Headers:
  X-API-Key: bf_xxxxx
  X-Store-Id: work-erp
상점 미지정 시에도 주문 등록은 가능합니다. 단, 여러 사이트를 운영한다면 상점을 등록하는 것을 권장합니다.

상점 전용 API 키

API 키를 만들 때 범위를 회사 전체 또는 상점 하나로 고릅니다(대시보드 > 설정 > API 키, 또는 상점 관리 카드의 「이 상점 전용 API 키 만들기」). 상점 전용 키는 그 상점의 계좌·거래·주문만 다룹니다. 다른 회사·다른 서버에서 운영하는 사이트에는 상점 전용 키를 두세요.

API회사 전체 키상점 전용 키
GET /transactions회사의 모든 거래그 상점 전용 계좌의 거래 + 공용 계좌 거래 중 그 상점으로 정해진 것. 공용 계좌 거래는 balance_after 가 null
GET /accounts회사의 모든 계좌그 상점 전용 계좌만 (공용 계좌는 나오지 않음)
POST /orderX-Store-Id 로 상점 지정(선택)상점은 키의 상점으로 고정. X-Store-Id 를 생략해도 되고, 다른 상점이면 403. bank_account_id 는 그 상점 전용 계좌 또는 공용 계좌만(아니면 400)
GET /orders · POST /order-exclude회사의 모든 주문그 상점 주문만 — 다른 상점 주문은 404
POST /cashbill · POST /taxinvoicetransaction_id 선택transaction_id 필수, 위 거래 범위 안의 거래만(밖이면 404)
POST /webhook (은행 알림 받기)쓸 수 있음쓸 수 없음 (403)

상점이 비활성이면 그 상점 전용 키는 403, 상점을 삭제하면 그 상점 전용 키도 함께 지워집니다.

// 다른 서버의 사이트 — 상점 전용 키 (X-Store-Id 없이도 그 상점 주문으로 등록)
POST /api/v1/order
Headers:
  X-API-Key: bf_yyyyy

거래 내역 조회

저장된 거래 내역을 조회합니다.

GET https://bankflow.co.kr/api/v1/transactions?from=2024-01-01&to=2024-12-31&type=deposit

Query Parameters

파라미터설명
from시작일 (YYYY-MM-DD)
to종료일 (YYYY-MM-DD)
typedeposit, withdrawal (선택)
account_id특정 계좌 ID (선택)
page페이지 번호
per_page페이지당 건수 (최대 100)

계좌 목록 조회

등록된 계좌 목록을 조회합니다.

GET https://bankflow.co.kr/api/v1/accounts

현금영수증 발행 API

외부 서비스에서 API로 현금영수증을 발행할 수 있습니다. 팝빌 연동이 완료되어 있어야 합니다.

POST https://bankflow.co.kr/api/v1/cashbill

요청 헤더

헤더설명
X-API-KeyAPI 키
Content-Typeapplication/json

요청 Body

{
  "amount": 11000,
  "trade_type": "income",
  "identity_num": "01012345678",
  "buyer_name": "홍길동",
  "item_name": "포인트 충전",
  "transaction_id": 123
}
필드타입필수설명
amountintegerY거래금액 (부가세 포함)
trade_typestringYincome (소득공제) / expense (지출증빙)
identity_numstringY식별번호 (휴대폰번호 또는 사업자번호)
buyer_namestring구매자명
item_namestring품목명
transaction_idintegerBankFlow 거래 ID (연결 시 증빙 상태 자동 업데이트)

응답

{
  "success": true,
  "message": "현금영수증이 발행되었습니다.",
  "data": {
    "approval_num": "TB0000043",
    "mgt_key": "BF260320143025abc1"
  }
}

세금계산서 발행 API

외부 서비스에서 API로 전자세금계산서를 발행할 수 있습니다. 팝빌 연동 + 공인인증서 등록이 필요합니다.

POST https://bankflow.co.kr/api/v1/taxinvoice

요청 Body

{
  "amount": 110000,
  "invoicee_corp_num": "1234567890",
  "invoicee_corp_name": "거래처상호",
  "invoicee_ceo_name": "대표자명",
  "invoicee_email": "tax@example.com",
  "item_name": "서비스 이용료",
  "write_date": "20260320",
  "transaction_id": 123
}
필드타입필수설명
amountintegerY합계금액 (부가세 포함)
invoicee_corp_numstringY공급받는자 사업자번호 (하이픈 없이)
invoicee_corp_namestringY공급받는자 상호
invoicee_ceo_namestringY공급받는자 대표자명
invoicee_emailstring공급받는자 이메일 (계산서 발송)
item_namestring품목명 (기본: 서비스 이용료)
write_datestring작성일자 yyyyMMdd (기본: 오늘)
transaction_idintegerBankFlow 거래 ID

응답

{
  "success": true,
  "message": "세금계산서가 발행되었습니다.",
  "data": {
    "mgt_key": "BF260320143025abc1"
  }
}
참고: 공급자 정보(사업자번호, 상호, 대표자)는 BankFlow 회사 설정에서 자동으로 채워집니다. 거래 내역 조회 API에서 tax_type, tax_status, tax_note 필드로 증빙 상태를 확인할 수 있습니다.

알림 웹훅 수신

알림 규칙에서 "외부 웹훅"을 선택하면, 조건에 매칭되는 거래 발생 시 지정한 URL로 POST 요청을 보냅니다.

설정 방법

  1. 대시보드 > 알림 규칙 > 규칙 추가
  2. 조건 설정 (예: 입금/출금 전체, 금액 초과 등)
  3. 알림 방식: "외부 웹훅" 또는 "웹 알림 + 외부 웹훅" 선택
  4. 웹훅 URL 입력 + 데이터 형식 선택 (JSON / 메시지)

요청 형식

POST 지정한 웹훅 URL

JSON 형식 (API 연동용)

헤더: Content-Type: application/json, X-BankFlow-Event: transaction.alert, 서명 헤더 X-BankFlow-Timestamp·X-BankFlow-Signature (설정의 Webhook Secret으로 서명 — 서명 검증 참고), 이벤트 ID 헤더 X-BankFlow-Event-Id

{
  "event": "transaction.alert",
  "event_id": "evt_Q3wErT6yUi9oPa2sDf5gHj8k",
  "type": "deposit",
  "amount": 880000,
  "counterpart": "홍길동",
  "balance_after": 8761172,
  "transacted_at": "2026-03-19 08:49:25",
  "rule_name": "모든 입금 알림",
  "transaction_id": 2345,
  "account_id": 1
}
필드타입설명
eventstringtransaction.alert (정상 알림) 또는 transaction.flagged (이상거래)
event_idstring이벤트 고유 ID — 재시도·재전송 때도 같은 값, 한 번만 처리 (이벤트 ID · 재전송)
typestringdeposit (입금), withdrawal (출금), note (비거래)
amountinteger거래 금액 (원)
counterpartstring|null상대방 (입금자명 또는 수취인)
balance_afterinteger|null거래 후 잔액
transacted_atstring거래 일시 (Y-m-d H:i:s)
rule_namestring매칭된 알림 규칙명
transaction_idintegerBankFlow 거래 ID
account_idintegerBankFlow 계좌 ID

메시지 형식 (사람 읽기용)

헤더: Content-Type: text/plain; charset=utf-8

[입금] 880,000원
홍길동 · 880,000원 · 잔액 8,761,172원
슬랙(Slack), 디스코드(Discord) 등의 Incoming Webhook에는 메시지 형식을 사용하세요. 자체 서비스 API 연동에는 JSON 형식을 권장합니다.

수신 측 구현 예시 (PHP)

// 웹훅 수신 엔드포인트
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);

if ($data['event'] === 'transaction.alert' && $data['type'] === 'deposit') {
    // 입금 알림 처리
    $amount = $data['amount'];
    $counterpart = $data['counterpart'];
    $balance = $data['balance_after'];

    // 예: DB 기록, 슬랙 알림, 포인트 충전 등
    logDeposit($amount, $counterpart, $balance);
}

// 200 OK 응답 (필수)
http_response_code(200);
echo 'OK';

응답 규격

웹훅을 정상 수신했으면 아래와 같이 응답합니다. 미응답 시 최대 3회 재전송됩니다.

항목값
HTTP 상태코드200
Response Body{"status": "success"} 또는 OK
재전송 정책: 최대 3회 시도 (즉시 → 10초 후 → 30초 후). 최종 실패 시 관리자에게 웹 알림이 발송됩니다.

거래 데이터 동기화 가이드

BankFlow의 거래 데이터를 자체 서비스 DB에 동기화하여 사용할 수 있습니다.

권장 테이블 구조

CREATE TABLE bankflow_transactions (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    bf_id BIGINT UNSIGNED NOT NULL COMMENT 'BankFlow 거래 ID',
    bank_account_id INT UNSIGNED DEFAULT NULL,
    type VARCHAR(20) NOT NULL DEFAULT 'deposit',
    amount BIGINT UNSIGNED NOT NULL DEFAULT 0,
    balance_after BIGINT DEFAULT NULL,
    counterpart VARCHAR(100) DEFAULT NULL,
    memo VARCHAR(500) DEFAULT NULL,
    transacted_at DATETIME NOT NULL,
    source VARCHAR(20) DEFAULT 'notification',
    is_flagged TINYINT(1) NOT NULL DEFAULT 0,
    synced_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_bf_id (bf_id),
    INDEX idx_type (type),
    INDEX idx_date (transacted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

필드 설명

필드타입설명
bf_idBIGINTBankFlow 거래 고유 ID (중복 방지 키)
typeVARCHAR(20)deposit (입금), withdrawal (출금), note (비거래 메모)
amountBIGINT거래 금액 (원)
balance_afterBIGINT거래 후 잔액 (없으면 NULL)
counterpartVARCHAR상대방 (입금자명 또는 수취인)
memoVARCHAR은행 적요
transacted_atDATETIME거래 일시
sourceVARCHARnotification (알림앱), api, manual (수동입력), csv (CSV업로드)
is_flaggedTINYINT이상거래 여부 (0/1)
type 필드 주의: ENUM('deposit', 'withdrawal') 대신 VARCHAR(20)을 권장합니다. note (비거래 메모) 등 추가 타입이 존재할 수 있습니다.

동기화 방식

거래 내역 조회 API를 주기적으로 호출하여 bf_id 기준으로 없는 데이터만 INSERT합니다.

최초 전체 동기화

// 100건씩 페이지네이션으로 전체 데이터 수집
GET /api/v1/transactions?from=2020-01-01&to=2026-12-31&page=1&per_page=100

// 응답
{
  "success": true,
  "data": {
    "transactions": [...],
    "total": 2246,      // 전체 건수
    "page": 1,          // 현재 페이지
    "per_page": 100     // 페이지당 건수
  }
}

// total_pages = ceil(total / per_page) = 23
// page 1~23까지 반복 호출

증분 동기화 (크론탭)

// 최근 3일만 조회하여 새로운 것만 INSERT
GET /api/v1/transactions?from=2026-03-15&to=2026-03-18&per_page=100

// bf_id UNIQUE KEY로 중복 자동 방지
// 5분 간격 크론탭 권장

자주 묻는 질문

자동매칭되는 기준은 무엇인가요?

입금 내역의 입금자명과 금액이 대기 중인 주문의 입금자명, 금액과 정확히 일치하는 주문이 1건일 때 자동매칭됩니다. 일치하는 주문이 없거나 2건 이상이면 매칭되지 않습니다.

매칭이 안 되는 경우는?

Webhook이 오지 않아요

API 호출 제한이 있나요?

구독 플랜에 따라 시간당 요청 수가 제한됩니다. 기본 1,000건/시간입니다.

© 2026 BankFlow. All rights reserved.