> ## Documentation Index
> Fetch the complete documentation index at: https://playcamp.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 벌크 플레이타임 세션 기록

> 최대 1,000건의 플레이타임 세션을 한 번에 기록합니다.

**부분 성공:** 각 항목은 독립적으로 처리되며 SUCCESS/SKIPPED/FAILED 상태를 반환합니다.
기존 `sessionId`가 존재하면 SKIPPED 처리됩니다 (중복 아님, 에러 아님).




## OpenAPI

````yaml /api_docs/openapi-ko.yaml post /v1/server/playtime/sessions/bulk
openapi: 3.0.3
info:
  title: PlayCamp SDK API
  description: |
    PlayCamp SDK API - 게임 분석 및 크리에이터 캠페인 연동 API

    ## 필수 연동 API (Server API)
    캠페인 진행을 위해 반드시 연동해야 하는 API 3개:
    - `POST /v1/server/sponsors` - 유저가 크리에이터를 부스트
    - `POST /v1/server/coupons/validate` - 쿠폰 코드 유효성 검사
    - `POST /v1/server/payments` - 인게임 결제 등록

    ## 인증 방식
    - **Client API**: `Authorization: Bearer {CLIENT_KEY_ID}:{CLIENT_SECRET}`
    - **Server API**: `Authorization: Bearer {SERVER_KEY_ID}:{SERVER_SECRET}`

    ## 서버
    - **Live**: https://sdk-api.playcamp.io (실제 데이터)
    - **Sandbox**: https://sandbox-sdk-api.playcamp.io (테스트 데이터)

    ## 키 타입
    - **Client 키**: 게임 클라이언트용 (읽기 전용 - 캠페인, 크리에이터 조회)
    - **Server 키**: 게임 서버용 (읽기/쓰기 - 쿠폰 사용, 결제 등록 등)

    ## 테스트 모드 (isTest)
    캠페인 실행 전에 `isTest: true` 파라미터를 사용하여 API 연동을 테스트할 수 있습니다.
    - 요청 파라미터 검증은 실제와 동일하게 수행
    - 모의 데이터를 반환하며 실제 DB에 기록되지 않음
    - 캠페인 시작 전 Sandbox 환경에서 연동 검증 후, 실제 캠페인 시 `isTest` 파라미터 제거
  version: 1.1.0
  contact:
    name: PlayCamp Support
servers:
  - url: https://sdk-api.playcamp.io
    description: Live Server
  - url: https://sandbox-sdk-api.playcamp.io
    description: Sandbox Server
  - url: http://localhost:3001
    description: Local Live Server
  - url: http://localhost:3003
    description: Local Sandbox Server
security: []
tags:
  - name: Health
    description: 서버 상태 확인
  - name: Client Campaign
    description: 캠페인 조회 (Client API)
  - name: Client Creator
    description: 크리에이터 조회 (Client API)
  - name: Client Coupon
    description: 쿠폰 유효성 검사 (Client API)
  - name: Client Sponsor
    description: 부스트 상태 조회 — Sponsor API (Client API)
  - name: Server Campaign
    description: 캠페인 조회 (Server API)
  - name: Server Creator
    description: 크리에이터 조회 (Server API)
  - name: Server Coupon
    description: 쿠폰 관리 (Server API)
  - name: Server Sponsor
    description: 부스트 관리 — Sponsor API (Server API)
  - name: Server Payment
    description: 결제 관리 (Server API)
  - name: Server Playtime
    description: 플레이타임 세션 관리 (Server API)
  - name: Server Webhook
    description: 웹훅 관리 (Server API)
  - name: Server Webview
    description: WebView 관리 (Server API)
paths:
  /v1/server/playtime/sessions/bulk:
    post:
      tags:
        - Server Playtime
      summary: 벌크 플레이타임 세션 기록
      description: |
        최대 1,000건의 플레이타임 세션을 한 번에 기록합니다.

        **부분 성공:** 각 항목은 독립적으로 처리되며 SUCCESS/SKIPPED/FAILED 상태를 반환합니다.
        기존 `sessionId`가 존재하면 SKIPPED 처리됩니다 (중복 아님, 에러 아님).
      operationId: serverCreateBulkPlaytimeSession
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBulkPlaytimeSessionRequest'
      responses:
        '200':
          description: 성공
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/BulkPlaytimeSessionResult'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'
      security:
        - ServerAuth: []
components:
  schemas:
    CreateBulkPlaytimeSessionRequest:
      type: object
      required:
        - sessions
      properties:
        sessions:
          type: array
          minItems: 1
          maxItems: 1000
          items:
            $ref: '#/components/schemas/CreatePlaytimeSessionRequest'
        callbackId:
          type: string
          description: 웹훅 추적용 ID
        isTest:
          type: boolean
          default: false
          description: 테스트 모드 (실제 데이터 생성 안 함)
    BulkPlaytimeSessionResult:
      type: object
      description: 벌크 플레이타임 세션 결과
      properties:
        totalRequested:
          type: integer
          description: 요청한 세션 항목 수
        successful:
          type: integer
          description: 성공한 세션 수
        failed:
          type: integer
          description: 실패한 세션 수
        skipped:
          type: integer
          description: 스킵된 세션 수 (중복 sessionId)
        results:
          type: array
          items:
            type: object
            properties:
              sessionId:
                type: string
              status:
                type: string
                enum:
                  - SUCCESS
                  - SKIPPED
                  - FAILED
              error:
                type: string
                description: 에러 메시지 (FAILED 상태일 때만)
    CreatePlaytimeSessionRequest:
      type: object
      required:
        - sessionId
        - userId
        - durationSeconds
        - startedAt
        - endedAt
      properties:
        sessionId:
          type: string
          description: 클라이언트에서 생성한 고유 세션 ID
        userId:
          type: string
          description: 사용자 ID
        durationSeconds:
          type: integer
          minimum: 1
          description: 세션 지속 시간 (초)
        startedAt:
          type: string
          format: date-time
          description: |
            세션 시작 시각 (ISO 8601 UTC 형식)
            - 형식: `YYYY-MM-DDTHH:mm:ss.sssZ`
            - 예시: `2024-01-15T10:30:00.000Z`
        endedAt:
          type: string
          format: date-time
          description: |
            세션 종료 시각 (ISO 8601 UTC 형식, `startedAt` 이상이어야 함)
            - 형식: `YYYY-MM-DDTHH:mm:ss.sssZ`
            - 예시: `2024-01-15T11:00:00.000Z`
        campaignId:
          type: string
          description: 캠페인 ID (선택). 미지정 시 프로젝트의 활성 캠페인 스폰서로 자동 귀속
        creatorKey:
          type: string
          pattern: ^[A-Z0-9]{5}$
          description: 크리에이터 키 (선택, 정확히 5자리 대문자 영숫자)
        platform:
          type: string
          enum:
            - iOS
            - Android
            - Web
            - Roblox
            - Other
          description: 플레이타임 플랫폼 (선택, 미지정 시 서버에서 `Other`로 기본 설정)
        metadata:
          type: object
          description: 임의의 키/값 메타데이터
          additionalProperties: true
    ValidationError:
      type: object
      required:
        - status
        - error
        - message
        - code
        - details
      properties:
        status:
          type: integer
          example: 400
        error:
          type: string
          example: Bad Request
        message:
          type: string
          example: Validation failed
        code:
          type: string
          example: VALIDATION_ERROR
        details:
          type: array
          items:
            type: object
            properties:
              path:
                type: string
                description: 오류가 발생한 필드 경로
              message:
                type: string
                description: 오류 메시지
          example:
            - path: userId
              message: Required
            - path: amount
              message: Expected number, received string
    Error:
      type: object
      required:
        - status
        - error
        - message
        - code
      properties:
        status:
          type: integer
          description: HTTP 상태 코드
        error:
          type: string
          description: HTTP 상태 이름
        message:
          type: string
          description: 상세 에러 메시지
        code:
          type: string
          description: |
            에러 코드:
            - `VALIDATION_ERROR`: 요청 파라미터 검증 실패
            - `BAD_REQUEST`: 잘못된 요청
            - `UNAUTHORIZED`: 인증 실패 (API 키 오류)
            - `FORBIDDEN`: 권한 없음
            - `NOT_FOUND`: 리소스를 찾을 수 없음
            - `CONFLICT`: 중복 리소스 (이미 존재)
            - `INTERNAL_ERROR`: 서버 내부 오류
        details:
          type: array
          description: 검증 오류 상세 (VALIDATION_ERROR의 경우)
          items:
            type: object
            properties:
              path:
                type: string
              message:
                type: string
      example:
        status: 404
        error: Not Found
        message: 'Payment not found: txn-12345'
        code: NOT_FOUND
  responses:
    ValidationError:
      description: 요청 파라미터 검증 실패
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
    Unauthorized:
      description: 인증 실패 (API 키 오류)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: 401
            error: Unauthorized
            message: Invalid API key
            code: UNAUTHORIZED
    Forbidden:
      description: 권한 없음 (Client 키로 Server API 접근 등)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: 403
            error: Forbidden
            message: Access denied
            code: FORBIDDEN
    RateLimited:
      description: 요청이 너무 많음 (요청 제한 초과)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: 429
            error: Too Many Requests
            message: Rate limit exceeded
            code: RATE_LIMITED
  securitySchemes:
    ServerAuth:
      type: http
      scheme: bearer
      description: 'Server API Key (format: {keyId}:{secret})'

````