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

# Create a transfer

> Atomically transfer assets from one participant to one or more recipients.

Moves funds from one participant or group to one or more recipients. The operation is zero-sum: the source's `AVAILABLE` balance is debited by the exact total credited across all recipients. You can include up to 100 recipients in a single call. A `description` is required (1-500 characters).

The source is identified by exactly one of `source_external_id`, `source_group_id`, or `source_participant_id`. Each recipient also requires exactly one of `external_id`, `group_id`, or `participant_id`. The asset must be linked to the program. Self-transfers (source and recipient are the same entity) return `400` with code `self_transfer`.

The transfer is atomic. If any leg fails (insufficient balance, inactive participant, inactive program), the entire transfer is rolled back and nothing moves. Both the source and every recipient must have `ACTIVE` status, and the program itself must be `ACTIVE`.

Pass an `idempotency_key` to safely retry requests. If a transfer with the same key already exists but the parameters differ, a `409` is returned with code `idempotency_conflict`.

For assets using `LOT` mode, lots are consumed FIFO from the source and new lots are created for each recipient. The lot vintage resets on transfer, so the recipient's lot `created_at` reflects the transfer time, not the original issuance.

<Note>
  For usage patterns and examples, see the [Transfers guide](/guides/transfers).
</Note>


## OpenAPI

````yaml POST /v1/transfers
openapi: 3.0.3
info:
  contact:
    email: support@scrip.dev
    name: Scrip Support
    url: https://scrip.dev/support
  description: >-
    Universal Incentive Infrastructure API for managing loyalty programs,
    rewards, and participant balances.


    Scrip provides a complete backend for building incentive and loyalty
    programs. Core concepts:

    - **Programs**: Containers for incentive logic (e.g., "Q1 Sales Bonus",
    "Customer Loyalty")

    - **Assets**: The currency or points being tracked (e.g., "Bonus Points",
    "Cash Rewards")

    - **Participants**: Users who earn and spend assets (identified by
    external_id)

    - **Groups**: Collections of participants for team-based incentives

    - **Rules**: Automated reward logic triggered by events

    - **Events**: Actions that trigger rule evaluation (e.g., "purchase",
    "referral")


    Response formats:

    - **Collection endpoints** return: {"data": [...], "pagination":
    {"has_more": true, "next_cursor": "..."}}

    - **Single-resource endpoints** return the resource directly

    - **Errors** return: {"code": "...", "message": "...", "details": {...}} —
    `details` is an optional object, present on input errors only
  license:
    name: Proprietary
    url: https://scrip.dev/license
  termsOfService: https://scrip.dev/terms
  title: Scrip API
  version: '1.0'
servers:
  - url: https://api.scrip.dev
security: []
tags:
  - description: >-
      Manage incentive programs. Programs are the top-level container for all
      incentive logic.
    name: Programs
  - description: >-
      Manage asset types (currencies, points). Assets define what participants
      can earn and spend.
    name: Assets
  - description: >-
      Manage participants and their balances. Participants are identified by
      external_id from your system.
    name: Participants
  - description: Manage participant groups for team-based incentives.
    name: Groups
  - description: >-
      Manage automated reward rules. Rules define conditions and actions
      triggered by events.
    name: Rules
  - description: Ingest events that trigger rule evaluation and reward distribution.
    name: Events
  - description: Transfer assets between participants.
    name: Transfers
  - description: Access ledger summaries and program activity reports.
    name: Reporting
  - description: >-
      Redeem participant balances for rewards. Supports raw amount redemptions
      and catalog item redemptions.
    name: Redemptions
  - description: >-
      Manage the reward catalog. Create and manage redeemable items with
      inventory tracking.
    name: Rewards
  - description: >-
      Schedule and manage automated event dispatching. Automations generate
      events on cron schedules, at specific times, or by evaluating participant
      state.
    name: Automations
  - description: >-
      Manage tier types and levels within programs. Tiers define status
      hierarchies that participants progress through based on qualification
      rules.
    name: Tiers
  - description: Inspect double-entry ledger records for auditing and reconciliation.
    name: Journal Entries
  - description: >-
      Manage webhook endpoints and delivery logs. Webhooks notify your
      application of real-time events via HTTP POST with HMAC-SHA256 signatures.
    name: Webhooks
paths:
  /v1/transfers:
    post:
      tags:
        - Transfers
      summary: Create a transfer
      description: >-
        Atomically transfer assets from one participant to one or more
        recipients.
      operationId: createTransfer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/handlers.CreateTransferRequest'
        description: Transfer details with source and recipients
        required: true
        x-originalParamName: request
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.TransferResponse'
          description: Transfer completed with journal entry ID
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrBadRequestResponse'
          description: >-
            Validation failed or self-transfer (code: validation_error |
            bad_request | self_transfer)
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnauthorizedResponse'
          description: 'Missing or invalid credentials (code: unauthorized)'
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrNotFoundResponse'
          description: 'Program, asset, or source participant not found (code: not_found)'
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrConflictResponse'
          description: 'Recipient inactive or idempotency conflict (code: conflict)'
        '415':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnsupportedMediaTypeResponse'
          description: 'Content-Type must be application/json (code: unsupported_media_type)'
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnprocessableResponse'
          description: >-
            Insufficient funds or program not active (code: insufficient_funds |
            program_inactive)
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrInternalResponse'
          description: 'Internal server error (code: internal_error)'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
components:
  schemas:
    handlers.CreateTransferRequest:
      additionalProperties: false
      properties:
        asset_id:
          description: Asset being transferred
          example: 550e8400-e29b-41d4-a716-446655440001
          format: uuid
          type: string
        description:
          description: Human-readable explanation of the transfer's purpose
          example: Monthly bonus distribution
          maxLength: 500
          minLength: 1
          type: string
        idempotency_key:
          description: Unique key to prevent duplicate transfers (optional)
          example: txn_abc123
          type: string
        program_id:
          description: Program this transfer belongs to
          example: 550e8400-e29b-41d4-a716-446655440000
          format: uuid
          type: string
        recipients:
          description: List of transfer recipients (1 to 100)
          items:
            $ref: '#/components/schemas/handlers.TransferRecipient'
          maxItems: 100
          minItems: 1
          type: array
        source_external_id:
          description: >-
            Source participant's external ID (mutually exclusive with
            `source_group_id` and `source_participant_id`)
          example: user_123
          type: string
        source_group_id:
          description: >-
            Source group UUID (mutually exclusive with `source_external_id` and
            `source_participant_id`)
          example: 550e8400-e29b-41d4-a716-446655440004
          format: uuid
          type: string
        source_participant_id:
          description: >-
            Source participant UUID (mutually exclusive with
            `source_external_id` and `source_group_id`)
          example: 550e8400-e29b-41d4-a716-446655440002
          format: uuid
          type: string
      required:
        - asset_id
        - description
        - program_id
        - recipients
      type: object
    handlers.TransferResponse:
      properties:
        asset_id:
          description: Asset that was transferred
          example: 550e8400-e29b-41d4-a716-446655440001
          format: uuid
          type: string
        journal_entry_id:
          description: Journal entry created for this transfer (use for audit trails)
          example: 550e8400-e29b-41d4-a716-446655440002
          format: uuid
          type: string
        recipient_count:
          description: Number of recipients in this transfer
          example: 5
          type: integer
        source_id:
          description: Scrip's UUID for the source participant
          example: 550e8400-e29b-41d4-a716-446655440003
          format: uuid
          type: string
        total_amount:
          description: Sum of all recipient amounts
          example: '500.00'
          type: string
      type: object
    handlers.ErrBadRequestResponse:
      additionalProperties: false
      properties:
        code:
          description: Code is the machine-readable error code
          example: bad_request
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: >-
            Details provides optional structured error context (field errors,
            etc.)
        message:
          description: Message is the human-readable error description
          example: Invalid request parameters
          type: string
      type: object
    handlers.ErrUnauthorizedResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: unauthorized
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Missing or invalid credentials
          type: string
      type: object
    handlers.ErrNotFoundResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: not_found
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Resource not found
          type: string
      type: object
    handlers.ErrConflictResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: conflict
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Resource already exists or state conflict
          type: string
      type: object
    handlers.ErrUnsupportedMediaTypeResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: unsupported_media_type
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Content-Type must be application/json
          type: string
      type: object
    handlers.ErrUnprocessableResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: unprocessable
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Business rule violation
          type: string
      type: object
    handlers.ErrInternalResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: internal_error
          type: string
        message:
          description: Message is the human-readable error description
          example: An internal error occurred
          type: string
      type: object
    handlers.TransferRecipient:
      properties:
        amount:
          description: >-
            Quantity to transfer to this recipient (decimal string for
            precision)
          example: '100.00'
          type: string
        external_id:
          description: >-
            Recipient participant's external ID (mutually exclusive with
            `group_id` and `participant_id`)
          example: user_456
          type: string
        group_id:
          description: >-
            Recipient group UUID (mutually exclusive with `external_id` and
            `participant_id`)
          example: 550e8400-e29b-41d4-a716-446655440005
          format: uuid
          type: string
        participant_id:
          description: >-
            Recipient participant UUID (mutually exclusive with `external_id`
            and `group_id`)
          example: 550e8400-e29b-41d4-a716-446655440003
          format: uuid
          type: string
      required:
        - amount
      type: object
    handlers.ErrorDetails:
      description: >-
        Optional structured details about the error. Always a JSON object: a
        `fields` array for validation errors, or flat
        field/reason/expected/received properties for other input errors.
      properties:
        expected:
          description: Expected value or format (non-validation input errors)
          example: uuid
          type: string
        field:
          description: Field name that caused the error (non-validation input errors)
          example: asset_id
          type: string
        fields:
          description: >-
            Fields lists each offending input field on validation_error
            responses.
          items:
            $ref: '#/components/schemas/handlers.ErrorFieldDetail'
          type: array
        reason:
          description: Machine-readable reason code (non-validation input errors)
          example: invalid
          type: string
        received:
          description: Value that was received (non-validation input errors)
          example: not-a-uuid
          type: string
      type: object
    handlers.ErrorFieldDetail:
      description: >-
        A single field-level error: which input field failed, why, and (where
        known) the expected and received values.
      properties:
        expected:
          description: >-
            Expected value or format. Usually a string; for "one of" constraints
            it

            is an array of the allowed values.
        field:
          description: Field name that caused the error
          example: amount
          type: string
        message:
          description: Human-readable explanation (validation errors only)
          example: This field is required
          type: string
        reason:
          description: Machine-readable reason code
          example: required
          type: string
        received:
          description: Value that was received
          example: '-10.00'
          type: string
      type: object
  securitySchemes:
    ApiKeyAuth:
      description: API key passed in the X-API-Key header.
      in: header
      name: X-API-Key
      type: apiKey
    BearerAuth:
      description: Bearer token passed in the Authorization header (e.g. "Bearer sk_...").
      in: header
      name: Authorization
      type: apiKey

````