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

# Grant credits in bulk

> Grants credits to up to 100 clients in one request. Each `clientId`
may appear only once in a batch.

Items are processed **independently and in order**. One failing item
does not roll back the others, so a response can report partial
success — always read `results[].success` per item rather than assuming
the whole batch went through. See
[Partial success](/guides/granting-credits#partial-success).




## OpenAPI

````yaml /api/v1/openapi.yaml post /v1/clients/credits/bulk
openapi: 3.0.3
info:
  title: Zenamu API v1
  version: '1.0'
  description: The Zenamu public REST API.
servers:
  - url: https://api.zenamu.com
    description: Production
security:
  - zenamuPublicKey: []
tags:
  - name: Classes
  - name: Workshops
  - name: Lecturers
  - name: Places
  - name: Clients
  - name: Credits and passes
  - name: Pass groups
paths:
  /v1/clients/credits/bulk:
    post:
      tags:
        - Credits and passes
      summary: Grant credits in bulk
      description: |
        Grants credits to up to 100 clients in one request. Each `clientId`
        may appear only once in a batch.

        Items are processed **independently and in order**. One failing item
        does not roll back the others, so a response can report partial
        success — always read `results[].success` per item rather than assuming
        the whole batch went through. See
        [Partial success](/guides/granting-credits#partial-success).
      operationId: addCreditsBulk
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkCreditsRequest'
            example:
              sendEmail: false
              items:
                - clientId: 123
                  customEntryCount:
                    count: 10
                    validityTimeValue: 1
                    validityTimeUnit: month
                  currency: CZK
                  price: 0
                - clientId: 456
                  customEntryCount:
                    count: 10
                    validityTimeValue: 1
                    validityTimeUnit: month
                  currency: CZK
                  price: 0
      responses:
        '200':
          description: >-
            Per-item results and a summary. Returned even when some items
            failed.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current one-minute window.
              schema:
                type: integer
                example: 100
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                minimum: 0
                example: 99
            X-RateLimit-Reset:
              description: Unix timestamp in seconds when the current window resets.
              schema:
                type: integer
                example: 1788336000
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkCreditsResponse'
              example:
                statusCode: 200
                message: Success
                data:
                  results:
                    - clientId: 123
                      success: true
                      numberOfCredits: 510
                      validTo: '2026-10-01'
                    - clientId: 456
                      success: false
                      error:
                        message: Client not found
                  summary:
                    total: 2
                    succeeded: 1
                    failed: 1
                    failedClientIds:
                      - 456
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/ForbiddenUltimate'
        '404':
          $ref: '#/components/responses/KeyNotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - zenamuSecretKey: []
components:
  schemas:
    BulkCreditsRequest:
      type: object
      required:
        - items
      properties:
        sendEmail:
          type: boolean
          default: true
          description: Applies to every item in the batch.
        items:
          type: array
          minItems: 1
          maxItems: 100
          description: Each `clientId` must be unique within the batch.
          items:
            $ref: '#/components/schemas/BulkCreditItem'
    BulkCreditsResponse:
      type: object
      properties:
        statusCode:
          type: integer
          example: 200
        message:
          type: string
          example: Success
        data:
          type: object
          properties:
            results:
              type: array
              items:
                $ref: '#/components/schemas/BulkCreditResult'
            summary:
              $ref: '#/components/schemas/BulkSummary'
    BulkCreditItem:
      type: object
      required:
        - clientId
        - customEntryCount
        - currency
        - price
      properties:
        clientId:
          type: integer
          minimum: 1
        customEntryCount:
          $ref: '#/components/schemas/CustomEntryCount'
        currency:
          type: string
          example: CZK
        price:
          type: number
          minimum: 0
    BulkCreditResult:
      type: object
      properties:
        clientId:
          type: integer
        success:
          type: boolean
        numberOfCredits:
          type: integer
          description: The client's new balance. Present when `success` is `true`.
        validTo:
          type: string
          format: date
          nullable: true
        error:
          type: object
          description: >-
            Present when `success` is `false`. Messages are safe summaries and
            may describe a permanent validation failure.
          properties:
            message:
              type: string
    BulkSummary:
      type: object
      properties:
        total:
          type: integer
        succeeded:
          type: integer
        failed:
          type: integer
        failedClientIds:
          type: array
          description: >-
            Client IDs of every failed item. IDs are unambiguous because a
            request cannot contain the same client twice. Inspect each
            corresponding `results[].error.message` before retrying.
          items:
            type: integer
    ErrorResponse:
      type: object
      required:
        - statusCode
        - message
      properties:
        statusCode:
          type: integer
          description: Repeats the HTTP status code.
        error:
          type: string
          description: >-
            Short label — `Internal Server Error` for `500`, `Too Many Requests`
            for `429`, `Error` otherwise.
        message:
          type: string
          description: >-
            Human-readable explanation. For `500` this is a fixed generic
            message; the detail is logged server-side.
    CustomEntryCount:
      type: object
      required:
        - count
        - validityTimeValue
        - validityTimeUnit
      description: How many credits or entries to grant, and for how long.
      properties:
        count:
          type: integer
          minimum: 1
          description: Number of credits or entries to add.
        validityTimeValue:
          type: integer
          minimum: 1
          description: >-
            How many `validityTimeUnit`s the grant stays valid, counted from
            now. Capped per unit: 36500 days, 5200 weeks, 1200 months, 100
            years.
        validityTimeUnit:
          type: string
          enum:
            - day
            - week
            - month
            - year
  responses:
    BadRequest:
      description: >-
        The request is malformed — a required parameter is missing, the
        `Authorization` header does not use the Bearer scheme, or body
        validation failed.
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 400
            error: Error
            message: 'dateFrom parameter is required (format: YYYY-MM-DD)'
    Unauthorized:
      description: No API key was sent.
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 401
            error: Error
            message: >-
              Missing access token. You must send your access token in the
              request header ('Authorization: Bearer YOUR_ACCESS_TOKEN' )
    ForbiddenUltimate:
      description: >-
        Your studio's plan does not allow the private API — it requires the
        Ultimate plan. See [Plans and access](/api#plans-and-access).
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 403
            error: Error
            message: The Zenamu API is only available on the Ultimate tariff.
    KeyNotFound:
      description: >-
        The API key was not recognized. Zenamu answers an unknown key with
        `404`, not `401` — see
        [Authentication](/api/authentication#authentication-errors).
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 404
            error: Error
            message: API key not found
    TooManyRequests:
      description: >-
        You exceeded 100 calls per minute on this endpoint. See [Rate
        limits](/api/rate-limits).
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 429
            error: Too Many Requests
            message: 'Rate limit exceeded: up to 100 requests per minute per endpoint.'
    InternalServerError:
      description: >-
        Unexpected server error. Retry with backoff if the call is safe to
        repeat.
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current one-minute window.
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
            minimum: 0
            example: 99
        X-RateLimit-Reset:
          description: Unix timestamp in seconds when the current window resets.
          schema:
            type: integer
            example: 1788336000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 500
            error: Internal Server Error
            message: >-
              We apologize, but there was an error on our end. If problems
              persist, please contact us at support@zenamu.com
  securitySchemes:
    zenamuPublicKey:
      type: http
      scheme: bearer
      description: >-
        Your **public API key** (`zen_pub_…`), sent as `Authorization: Bearer
        <key>`. Browser-safe. See [Authentication](/api/authentication).
    zenamuSecretKey:
      type: http
      scheme: bearer
      description: >-
        Your **secret API key** (`zen_live_…`), sent as `Authorization: Bearer
        <key>`. Backend-to-backend only — never expose it in a browser. See
        [Authentication](/api/authentication).

````