# BanqPipe Public API v1

> Base URL: `https://api.banqpipe.com/api/v1`

---

## 서비스 개요

BanqPipe는 **연락처 이체(전화번호 송금)** 기반의 자동 입금 처리 시스템입니다.

기존 계좌이체와 달리, 입금자는 수취인의 **전화번호**로 송금합니다. BanqPipe는 수취 디바이스에서 입금 SMS를 실시간 감지하여 세션과 자동 매칭하고, 매칭된 입금 건에 대해 수취인 계좌로의 이체를 자동 처리합니다.

**처리 흐름 요약**:

1. 파트너가 API로 입금 세션을 생성하면, BanqPipe가 수취 디바이스(전화번호)와 계좌를 자동 배정합니다.
2. 파트너는 응답으로 받은 수취인 전화번호를 입금자에게 안내합니다.
3. 입금자가 은행 앱에서 해당 전화번호로 연락처 이체를 실행합니다.
4. 수취 디바이스가 입금 SMS를 수신하면, BanqPipe가 금액과 입금자명으로 세션을 매칭합니다.
5. 매칭 완료 후 처리 결과를 Callback URL로 통보합니다.

---

## 인증

모든 API 요청에는 `X-API-Key` 헤더가 필요합니다.

```
X-API-Key: bpk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

API Key는 관리자가 파트너 콘솔에서 발급합니다.  
파트너 상태가 **APPROVED**인 경우에만 API 호출이 허용됩니다.

### 인증 실패 응답

| HTTP 상태 | 조건 |
|-----------|------|
| `401 Unauthorized` | API Key 누락 또는 유효하지 않음 |
| `403 Forbidden` | 파트너 상태가 APPROVED가 아님 (PENDING, SUSPENDED 등) |

---

## 엔드포인트

### 1. 입금 세션 생성

```
POST /deposit/sessions
```

입금 세션을 생성하고 디바이스(전화번호)와 수취 계좌를 자동 배정합니다.

#### 요청 바디

| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| `amount` | `number` | O | 입금 금액 (원) |
| `sender_name` | `string` | O | 입금자 이름 |
| `sender_phone` | `string` | X | 입금자 전화번호 (SMS 발신인 판별용) |
| `sender_bank` | `string` | X | 입금자 은행 |
| `recipient` | `object` | X | 수취인 지정 시 사용 (아래 참조) |

**`recipient` 객체** (선택):

| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| `bank` | `string` | O | 수취 은행명 |
| `account_number` | `string` | O | 수취 계좌번호 |
| `holder` | `string` | O | 수취인 예금주 |

#### 동작 모드

- **Mode A — 전체 자동 배정**: `recipient`를 생략하면 디바이스와 수취 계좌 모두 라운드 로빈으로 자동 배정됩니다.
- **Mode B — 수취인 지정**: `recipient`를 포함하면 해당 수취인 정보로 계좌를 찾거나 새로 생성하고, 디바이스만 라운드 로빈으로 배정됩니다.

> 라운드 로빈은 파트너 소속 리소스 중 WAITING 세션이 가장 적은 것을 선택합니다.  
> 디바이스는 ONLINE 상태를 우선으로 배정됩니다.

#### 요청 예시

**Mode A (전체 자동)**
```json
{
  "amount": 50000,
  "sender_name": "홍길동",
  "sender_phone": "01012345678",
  "sender_bank": "신한은행"
}
```

**Mode B (수취인 지정)**
```json
{
  "amount": 100000,
  "sender_name": "홍길동",
  "sender_phone": "01012345678",
  "recipient": {
    "bank": "국민은행",
    "account_number": "123456789012",
    "holder": "김철수"
  }
}
```

#### 응답 (200 OK)

```json
{
  "session_id": "dp_a1b2c3d4-...",
  "status": "WAITING",
  "recipient_name": "김철수",
  "recipient_phone": "01098765432",
  "amount": 50000,
  "expires_at": "2026-04-22T15:30:00.000Z"
}
```

| 필드 | 설명 |
|------|------|
| `session_id` | 입금 세션 고유 ID |
| `status` | 세션 상태 (생성 직후 `WAITING`) |
| `recipient_name` | 배정된 수취인 이름 — 입금자에게 안내 |
| `recipient_phone` | 배정된 디바이스 전화번호 — 입금자에게 안내 |
| `amount` | 입금 금액 |
| `expires_at` | 세션 만료 시각 (UTC) |

#### 에러 응답

| HTTP 상태 | 조건 |
|-----------|------|
| `400 Bad Request` | `amount` 또는 `sender_name` 누락, 배정 가능한 디바이스/계좌 없음 |

```json
{
  "statusCode": 400,
  "message": "사용 가능한 디바이스가 없습니다.",
  "error": "Bad Request"
}
```

---

### 2. Callback URL 등록/변경

```
PUT /deposit/callback-url
```

입금 세션 상태 변경 시 통보받을 Callback URL을 등록하거나 변경합니다.

#### 요청 바디

| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| `callback_url` | `string` | O | 콜백을 수신할 URL (https 권장) |

#### 요청 예시

```json
{
  "callback_url": "https://your-server.com/webhook/banqpipe"
}
```

#### 응답 (200 OK)

```json
{
  "success": true,
  "callback_url": "https://your-server.com/webhook/banqpipe"
}
```

#### 에러 응답

| HTTP 상태 | 조건 |
|-----------|------|
| `400 Bad Request` | `callback_url` 누락 또는 유효하지 않은 URL |
| `401 Unauthorized` | API Key 누락/유효하지 않음 |
| `403 Forbidden` | 파트너 미승인 |

---

### 3. 입금 세션 취소

```
PUT /deposit/sessions/:id/cancel
```

WAITING 상태의 입금 세션을 취소합니다. 본인(파트너) 소유 세션만 취소 가능합니다.

#### 경로 파라미터

| 파라미터 | 설명 |
|----------|------|
| `id` | 세션 ID (`session_id`) |

#### 응답 (200 OK)

```json
{
  "session_id": "dp_a1b2c3d4-...",
  "status": "CANCELLED"
}
```

#### 에러 응답

| HTTP 상태 | 조건 |
|-----------|------|
| `400 Bad Request` | WAITING 상태가 아닌 세션 취소 시도 |
| `404 Not Found` | 세션이 존재하지 않거나 본인 소유가 아님 |

> **참고**: MATCHED 이후 상태의 세션은 취소할 수 없습니다. SMS 매칭이 완료된 세션은 처리가 진행되므로, 취소가 필요한 경우 WAITING 상태일 때 즉시 취소하세요.

---

### 4. 입금 세션 조회

```
GET /deposit/sessions/:id
```

생성한 입금 세션의 현재 상태를 조회합니다. 본인(파트너) 소유 세션만 조회 가능합니다.

#### 경로 파라미터

| 파라미터 | 설명 |
|----------|------|
| `id` | 세션 ID (`session_id`) |

#### 응답 (200 OK)

```json
{
  "session_id": "dp_a1b2c3d4-...",
  "status": "COMPLETED",
  "amount": 50000,
  "sender_name": "홍길동",
  "sender_phone": "01012345678",
  "created_at": "2026-04-22T15:00:00.000Z",
  "expires_at": "2026-04-22T15:30:00.000Z",
  "matched_at": "2026-04-22T15:05:23.000Z"
}
```

#### 에러 응답

| HTTP 상태 | 조건 |
|-----------|------|
| `404 Not Found` | 세션이 존재하지 않거나 본인 소유가 아님 |

---

## 세션 상태 (Status)

| 상태 | 설명 |
|------|------|
| `WAITING` | 입금 대기 중 |
| `MATCHED` | SMS 매칭 완료, 처리 중 |
| `COMPLETED` | 입금 처리 완료 |
| `FAILED` | 처리 실패 |
| `EXPIRED` | 만료 (기본 30분) |
| `CANCELLED` | 파트너 또는 API에 의해 취소 |

상태 흐름:  
`WAITING` → `MATCHED` → `COMPLETED`  
`WAITING` → `EXPIRED`  
`WAITING` → `CANCELLED`  
`MATCHED` → `FAILED`

---

## 콜백 (Webhook)

파트너 콘솔 설정에서 **Callback URL**을 등록하면, 세션이 종료 상태에 도달할 때 해당 URL로 `POST` 요청이 전송됩니다.

### 트리거 조건

콜백은 다음 상태 전환 시 발생합니다:

- `COMPLETED` — 입금 처리 완료
- `FAILED` — 처리 실패
- `EXPIRED` — 세션 만료
- `CANCELLED` — 세션 취소

### 콜백 페이로드

**SESSION_COMPLETED**
```json
{
  "event": "SESSION_COMPLETED",
  "session_id": "dp_a1b2c3d4-...",
  "amount": 50000,
  "sender_name": "홍길동",
  "completed_at": "2026-04-22T15:05:30.000Z"
}
```

**SESSION_FAILED**
```json
{
  "event": "SESSION_FAILED",
  "session_id": "dp_a1b2c3d4-...",
  "amount": 50000,
  "sender_name": "홍길동",
  "failed_at": "2026-04-22T15:06:00.000Z"
}
```

**SESSION_EXPIRED**
```json
{
  "event": "SESSION_EXPIRED",
  "session_id": "dp_a1b2c3d4-...",
  "amount": 50000,
  "sender_name": "홍길동",
  "expired_at": "2026-04-22T15:30:00.000Z"
}
```

**SESSION_CANCELLED**
```json
{
  "event": "SESSION_CANCELLED",
  "session_id": "dp_a1b2c3d4-...",
  "amount": 50000,
  "sender_name": "홍길동",
  "cancelled_at": "2026-04-22T15:10:00.000Z"
}
```

### 재시도 정책

콜백 전송이 실패하면 지수 백오프(exponential backoff)로 최대 **5회** 재시도합니다.

| 시도 | 대기 시간 |
|------|-----------|
| 1차 재시도 | ~2초 |
| 2차 재시도 | ~4초 |
| 3차 재시도 | ~8초 |
| 4차 재시도 | ~16초 |
| 5차 재시도 | ~32초 |

HTTP 2xx 응답을 성공으로 간주합니다.

---

## 통합 플로우 예시

```
위젯(클라이언트)                       BanqPipe API                     파트너 서버
     │                                    │                                │
     │  POST /deposit/sessions            │                                │
     │  { amount, sender_name, ... }      │                                │
     │ ──────────────────────────────────> │                                │
     │                                    │  디바이스/계좌 라운드 로빈 배정    │
     │  { session_id, recipient_name,     │                                │
     │    recipient_phone, ... }          │                                │
     │ <────────────────────────────────── │                                │
     │                                    │                                │
     │  입금자에게 수취인 정보 표시           │                                │
     │  "김철수에게 01098765432로            │                                │
     │   50,000원을 연락처 이체해주세요"      │                                │
     │                                    │                                │
     │         ... 입금자가 이체 ...        │                                │
     │                                    │                                │
     │                                    │  SMS 수신 → 매칭 → 처리         │
     │                                    │                                │
     │                                    │  POST callback_url             │
     │                                    │  { event: SESSION_COMPLETED }  │
     │                                    │ ──────────────────────────────> │
     │                                    │                                │
     │  GET /deposit/sessions/:id         │                                │
     │ ──────────────────────────────────> │                                │
     │  { status: "COMPLETED" }           │                                │
     │ <────────────────────────────────── │                                │
```

---

## 에러 코드 요약

| HTTP 상태 | 의미 |
|-----------|------|
| `200` | 성공 |
| `400` | 잘못된 요청 (필수 파라미터 누락, 리소스 부족) |
| `401` | 인증 실패 (API Key 누락/유효하지 않음) |
| `403` | 권한 없음 (파트너 미승인) |
| `404` | 리소스를 찾을 수 없음 |
