> ## Documentation Index
> Fetch the complete documentation index at: https://surf-dcinside-api.kr.ask.surf/llms.txt
> Use this file to discover all available pages before exploring further.

# Health

> Service state, versions in use and the last cycle received.

<div style={{ maxWidth: 760 }}>
  <h2 style={{ fontSize: "22px", marginBottom: 8 }}>Overview</h2>

  The **Health** API returns the state of the service, the model and weights in use, and the last cycle call we received. It is not needed for scoring: DCinside can use it for its own monitoring, for example to check that the last cycle arrived.

  <Note>
    Surf's own watchdog does not rely on this endpoint. It watches the arrival time of the latest cycle call on a separate schedule, and posts to Slack if no call arrives for 15 minutes.
  </Note>

  ***

  <h2 style={{ fontSize: "22px", marginBottom: 8 }}>Response Attributes</h2>

  <ResponseField name="status" type="string" required>
    `degraded` means the service is up but something needs a look, for example scoring is slower than usual. One of `ok`, `degraded`.
  </ResponseField>

  <ResponseField name="time" type="string" required>
    Our clock.
  </ResponseField>

  <ResponseField name="api_version" type="string" required>
    API major version.
  </ResponseField>

  <ResponseField name="model_version" type="string" required>
    Model in use.
  </ResponseField>

  <ResponseField name="weights_version" type="string" required>
    Weights in force.
  </ResponseField>

  <ResponseField name="last_cycle_id" type="string | null" required>
    The last cycle call received, or `null` before the first.
  </ResponseField>

  <ResponseField name="last_cycle_received_at" type="string | null" required>
    When that call arrived, or `null` before the first.
  </ResponseField>

  ***
</div>

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET \
    --url "https://rtb.example.com/v1/health" \
    --header "Authorization: <api-key>"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://rtb.example.com/v1/health",
      headers={"Authorization": "<api-key>"},
  )
  health = response.json()
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://rtb.example.com/v1/health", {
    headers: { Authorization: "<api-key>" },
  });
  const health = await response.json();
  ```
</RequestExample>

<ResponseExample>
  ```json 200 — ok theme={null}
  {
    "status": "ok",
    "time": "2026-09-29T02:05:30+09:00",
    "api_version": "1",
    "model_version": "m0924-1",
    "weights_version": "w-1",
    "last_cycle_id": "20260929T0205",
    "last_cycle_received_at": "2026-09-29T02:05:03+09:00"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml openapi.json GET /v1/health
openapi: 3.0.3
info:
  title: DCinside RTB API
  description: >-
    Publish scores for DCinside's Real-Time Best candidate pool. DCinside makes
    one call per five-minute cycle and reads the scores in the response. Version
    1 is a proposal for the technical exchange with DCinside: calls, field names
    and limits can change until both sides agree.
  version: 1.0.0
servers:
  - url: https://{host}
    description: Issued by Surf together with the API key.
    variables:
      host:
        default: rtb.example.com
        description: >-
          Host name issued by Surf for the environment (rehearsal or
          production). The default is a placeholder.
security:
  - ApiKey: []
tags:
  - name: Scoring
    description: One call per five-minute cycle, and re-reading a stored cycle.
  - name: Images
    description: Post images, uploaded once per post, separately from scoring.
  - name: Outcomes
    description: Not in MVP scope. How placed posts performed. Used for learning.
  - name: Weights
    description: Not in MVP scope. The weights of the publish score.
  - name: Health
    description: Service state.
paths:
  /v1/health:
    get:
      tags:
        - Health
      summary: Health
      description: Service state, and the last cycle we received. Not needed for scoring.
      operationId: getHealth
      responses:
        '200':
          description: Service state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
              example:
                status: ok
                time: '2026-09-29T02:05:30+09:00'
                api_version: '1'
                model_version: m0924-1
                weights_version: w-1
                last_cycle_id: 20260929T0205
                last_cycle_received_at: '2026-09-29T02:05:03+09:00'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  schemas:
    Health:
      type: object
      properties:
        status:
          type: string
          enum:
            - ok
            - degraded
          example: ok
          description: >-
            `degraded` means the service is up but something needs a look, for
            example scoring is slower than usual.
        time:
          type: string
          format: date-time
          pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+09:00$
          description: Our clock.
          example: '2026-09-29T02:05:30+09:00'
        api_version:
          type: string
          example: '1'
          description: API major version.
        model_version:
          type: string
          example: m0924-1
          description: Model in use.
        weights_version:
          type: string
          example: w-1
          description: Weights in force.
        last_cycle_id:
          type: string
          nullable: true
          example: 20260929T0205
          description: The last cycle call received, or `null` before the first.
        last_cycle_received_at:
          type: string
          format: date-time
          pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+09:00$
          description: When that call arrived, or `null` before the first.
          example: '2026-09-29T02:05:03+09:00'
          nullable: true
      required:
        - status
        - time
        - api_version
        - model_version
        - weights_version
        - last_cycle_id
        - last_cycle_received_at
    Error:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
      required:
        - error
    ErrorBody:
      type: object
      properties:
        code:
          type: string
          example: bad_request
          description: Machine-readable code. See Errors.
        message:
          type: string
          example: 2 fields failed validation
          description: Human-readable summary.
        fields:
          type: array
          items:
            $ref: '#/components/schemas/ErrorField'
          description: Every failing field, when the error is about the body.
      required:
        - code
        - message
    ErrorField:
      type: object
      properties:
        path:
          type: string
          example: candidates[0].created_at
          description: Path of the failing field.
        problem:
          type: string
          example: missing +09:00 offset
          description: What is wrong with it.
      required:
        - path
        - problem
  responses:
    Unauthorized:
      description: The API key is missing or unknown.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: unauthorized
              message: API key missing or unknown
    Forbidden:
      description: The key has no scope for this call.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: forbidden
              message: this key cannot call PUT /v1/weights
    RateLimited:
      description: >-
        Too many calls. Wait for `Retry-After` seconds, then repeat the same
        call.
      headers:
        Retry-After:
          description: Seconds to wait.
          schema:
            type: integer
            example: 10
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: rate_limited
              message: too many calls, retry in 10 s
    ServerError:
      description: Our failure. No scores. DCinside skips the cycle and our alert fires.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: server_error
              message: internal error
  securitySchemes:
    ApiKey:
      type: apiKey
      name: Authorization
      in: header
      description: >-
        The API key issued for the environment, sent as the whole header value.
        Two keys are valid during a rotation.

````