인게임 결제 내역을 등록합니다. 등록된 결제는 유저의 부스트 중인 크리에이터에게 자동 귀속됩니다.
1. 인게임 결제 완료 → 2. API로 결제 정보 전송 → 3. 크리에이터 귀속 + 정산
결제 등록
요청
curl -X POST "https://sandbox-sdk-api.playcamp.io/v1/server/payments" \
-H "Authorization: Bearer ak_server_xxx:secret" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_12345",
"transactionId": "txn_abc123",
"productId": "gem_pack_100",
"productName": "100 보석 팩",
"amount": 9900,
"currency": "KRW",
"platform": "Android",
"distributionType": "MOBILE_STORE",
"purchasedAt": "2024-01-15T10:30:00.000Z"
}'
const payment = await server.payments.create({
userId: 'user_12345',
transactionId: 'txn_abc123',
productId: 'gem_pack_100',
productName: '100 보석 팩',
amount: 9900,
currency: 'KRW',
platform: 'Android',
distributionType: 'MOBILE_STORE',
purchasedAt: new Date('2024-01-15T10:30:00Z'),
});
purchasedAt, _ := time.Parse(time.RFC3339, "2024-01-15T10:30:00Z")
payment, err := server.Payments.Create(ctx, playcamp.CreatePaymentParams{
UserID: "user_12345",
TransactionID: "txn_abc123",
ProductID: "gem_pack_100",
ProductName: playcamp.String("100 보석 팩"),
Amount: 9900,
Currency: "KRW",
Platform: playcamp.PaymentPlatformAndroid,
DistributionType: playcamp.String("MOBILE_STORE"),
PurchasedAt: purchasedAt,
})
응답 (201 Created)
{
"data": {
"id": 1234,
"transactionId": "txn_abc123",
"userId": "user_12345",
"productId": "gem_pack_100",
"productName": "100 보석 팩",
"amount": 9900,
"currency": "KRW",
"platform": "Android",
"campaignId": "campaign_001",
"creatorKey": "ABC12",
"status": "COMPLETED",
"purchasedAt": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:05.000Z"
}
}
필수 파라미터
| 필드 | 타입 | 설명 |
|---|
userId | string | 게임 내 유저 식별자 |
transactionId | string | 플랫폼별 고유 거래 ID (중복 방지용) |
productId | string | 상품 ID |
amount | number | 결제 금액 |
currency | string | 통화 코드 (ISO 4217: USD, KRW 권장) |
platform | string | 플랫폼 (iOS, Android, Web, Roblox, Other) |
distributionType | string | 유통 타입 (아래 참조) |
purchasedAt | string | 실제 결제 발생 시각 (ISO 8601) |
선택 파라미터
| 필드 | 타입 | 설명 |
|---|
productName | string | 상품명 |
callbackId | string | 웹훅 추적용 ID (웹훅 이벤트에 포함됨) |
isTest | boolean | 테스트 모드 (실제 데이터 생성 안 함) |
유통 타입 (필수)
결제 등록 시 distributionType은 필수 파라미터입니다. 정산 계산에 사용됩니다.
| 값 | 설명 | 스토어 수수료 |
|---|
MOBILE_STORE | 모바일 외부 스토어 (Google Play, App Store) | 30% |
PC_STORE | PC 외부 스토어 (Steam 등) | 30% |
MOBILE_SELF_STORE | 모바일 자체 결제 | 0% |
PC_SELF_STORE | PC 자체 스토어 | 0% |
정산 계산: Net Amount = 결제금액 × (1 - 스토어 수수료) 후, PlayCamp 플랫폼 수수료와 크리에이터 수수료가 별도 적용됩니다.중요: 정확한 정산을 위해 실제 결제가 발생한 유통 채널에 맞는 값을 지정하세요.
통화 변환
USD가 아닌 통화의 경우 자동으로 USD로 변환됩니다 (amountUsd 필드).
// KRW 결제 예시
{ amount: 9900, currency: "KRW" }
// → amountUsd: 7.62 (자동 계산)
결제 환불
curl -X POST "https://sandbox-sdk-api.playcamp.io/v1/server/payments/txn_abc123/refund" \
-H "Authorization: Bearer ak_server_xxx:secret" \
-H "Content-Type: application/json" \
-d '{}'
const refund = await server.payments.refund('txn_abc123');
payment, err := server.Payments.Refund(ctx, "txn_abc123", nil)
환불 시 정산에서 해당 금액이 차감됩니다.
에러 처리
| HTTP | 코드 | 설명 |
|---|
| 400 | VALIDATION_ERROR | 필수 파라미터 누락 |
| 409 | CONFLICT | 중복된 transactionId |
벌크 결제
최대 1,000건의 결제를 한 번에 등록할 수 있습니다.
요청
curl -X POST "https://sandbox-sdk-api.playcamp.io/v1/server/payments/bulk" \
-H "Authorization: Bearer ak_server_xxx:secret" \
-H "Content-Type: application/json" \
-d '{
"payments": [
{
"userId": "user_1",
"transactionId": "txn_001",
"productId": "gem_pack_100",
"amount": 9900,
"currency": "KRW",
"platform": "iOS",
"distributionType": "MOBILE_STORE",
"purchasedAt": "2026-03-17T00:00:00Z"
},
{
"userId": "user_2",
"transactionId": "txn_002",
"productId": "gem_pack_200",
"amount": 19900,
"currency": "KRW",
"platform": "Android",
"distributionType": "MOBILE_STORE",
"purchasedAt": "2026-03-17T00:00:00Z"
}
],
"callbackId": "bulk-001"
}'
const result = await server.payments.createBulk({
payments: [
{
userId: 'user_1',
transactionId: 'txn_001',
productId: 'gem_pack_100',
amount: 9900,
currency: 'KRW',
platform: 'iOS',
distributionType: 'MOBILE_STORE',
purchasedAt: '2026-03-17T00:00:00Z',
},
{
userId: 'user_2',
transactionId: 'txn_002',
productId: 'gem_pack_200',
amount: 19900,
currency: 'KRW',
platform: 'Android',
distributionType: 'MOBILE_STORE',
purchasedAt: '2026-03-17T00:00:00Z',
},
],
callbackId: 'bulk-001', // optional
});
console.log(result.totalRequested); // 2
console.log(result.successful); // 성공 건수
console.log(result.failed); // 실패 건수
console.log(result.skipped); // 스킵 건수
purchasedAt, _ := time.Parse(time.RFC3339, "2026-03-17T00:00:00Z")
result, err := server.Payments.CreateBulk(ctx, playcamp.CreateBulkPaymentParams{
Payments: []playcamp.CreatePaymentParams{
{
UserID: "user_1",
TransactionID: "txn_001",
ProductID: "gem_pack_100",
Amount: 9900,
Currency: "KRW",
Platform: playcamp.PaymentPlatformIOS,
DistributionType: playcamp.String("MOBILE_STORE"),
PurchasedAt: purchasedAt,
},
{
UserID: "user_2",
TransactionID: "txn_002",
ProductID: "gem_pack_200",
Amount: 19900,
Currency: "KRW",
Platform: playcamp.PaymentPlatformAndroid,
DistributionType: playcamp.String("MOBILE_STORE"),
PurchasedAt: purchasedAt,
},
},
CallbackID: "bulk-001", // optional
})
응답 (200 OK)
{
"data": {
"totalRequested": 2,
"successful": 2,
"failed": 0,
"skipped": 0,
"results": [
{
"transactionId": "txn_001",
"status": "SUCCESS",
"data": { "id": 1234, "transactionId": "txn_001", "userId": "user_1" }
},
{
"transactionId": "txn_002",
"status": "SUCCESS",
"data": { "id": 1235, "transactionId": "txn_002", "userId": "user_2" }
}
]
}
}
벌크 결제 파라미터
| 필드 | 타입 | 설명 |
|---|
payments | array | 결제 항목 배열 (최대 1,000건). 각 항목은 단건 결제와 동일한 필수 파라미터 |
callbackId | string | 웹훅 추적용 ID (optional) |
isTest | boolean | 테스트 모드 (optional) |
결과 상태
| 상태 | 설명 |
|---|
SUCCESS | 결제 등록 성공 |
SKIPPED | 이미 존재하는 transactionId (중복) |
FAILED | 등록 실패 (유효성 검증 오류 등) |
벌크 결제는 부분 성공을 지원합니다. 일부 항목이 실패해도 나머지 항목은 정상 처리됩니다. 벌크 결제 완료 시 payment.bulk_created 웹훅 이벤트가 발생합니다.