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

# Create a single payout (mock)

> Create a single-beneficiary payout. The mock provider returns the Payout resource and either transitions it through PENDING → PROCESSING → PAID asynchronously, or to a deterministic outcome if magic triggers are used. **Moves no real money.**



## OpenAPI

````yaml /openapi.json post /v1/payouts
openapi: 3.1.0
info:
  title: Payroll API
  description: >

    ## Payroll Infrastructure API for Latin America


    **Stripe for payroll** — embedded payroll calculation infrastructure.


    ### Overview


    This API performs payroll calculations for Mexico, Colombia, Brazil,
    Argentina,

    and Chile. It is a **pure computation engine**: give it employee data, get
    back

    a fully itemized payroll breakdown.


    ### Key concepts


    - **Scheme** — A country-specific payroll ruleset (e.g., Mexico `ordinario`,
    Colombia `integral`).
      Use `GET /v1/payroll/schemes/{country}` to discover available schemes.
    - **Calculation** — A single employee payroll run for one period.

    - **Audit trail** — A step-by-step trace of every formula evaluated.
    Required for
      legal compliance in most Latin American countries.

    ### Decimal precision


    All monetary amounts are returned as **JSON strings** (not numbers) to
    prevent

    floating-point precision loss in client languages. Parse them with your
    language's

    `Decimal` type before doing any arithmetic.


    ```

    ✅ correct:  {"net_salary": "20039.25"}

    ❌ wrong:    {"net_salary": 20039.25}  // could lose precision

    ```


    ### Authentication


    All endpoints require a Bearer API key:

    ```

    Authorization: Bearer your_api_key_here

    ```


    ### Error format


    All errors follow a consistent structure:

    ```json

    {
      "error": {
        "code": "SCHEME_NOT_FOUND",
        "message": "Human-readable description",
        "details": {},
        "request_id": "abc123"
      }
    }

    ```


    Use the `code` field (not the HTTP status) for programmatic error handling.

    The `request_id` links to server logs — include it when contacting support.


    ### Payouts (mock provider)


    The `/v1/payouts` surface lets you pay an employee their `net_salary` after
    a

    calculation. In v1 every payout is handled by an **in-process mock
    provider** —

    no real funds are moved. Every response is marked with `mock: true` in the
    body

    and `X-Clevis-Mock: true` as a response header.


    - Magic `external_id` prefixes (`MOCK_REJECT_INTAKE_`, `MOCK_REJECT_BANK_`,
      `MOCK_SLOW_`, `MOCK_STUCK_`, `MOCK_OK_`) trigger deterministic outcomes for
      demos and tests.
    - `processing.step_seconds: 0` makes the payout transition to its terminal
      status synchronously before the response is returned.
    - Idempotency is supported via the `Idempotency-Key` header or via the
      `external_id` field (per API key).

    See `docs/specs/04_payout_mock_endpoint.md` for the full contract. The real

    dLocal integration will be a config flip behind the same interface; this

    client-facing contract does not change.
  contact:
    name: Payroll API Support
    email: api@payroll.io
  license:
    name: Proprietary
  version: 1.0.0
servers: []
security: []
tags:
  - name: Payroll
    description: Payroll calculation endpoints. All monetary values are JSON strings.
  - name: Payouts
    description: >-
      Single-beneficiary payout endpoints backed by an in-process **mock**
      provider in v1 — no real funds are moved. Every response carries `mock:
      true` and the `X-Clevis-Mock: true` header. Magic trigger values (e.g.
      `external_id` prefixed with `MOCK_REJECT_BANK_`) force deterministic
      outcomes for demos and tests.
  - name: Schemes & Health
    description: Discover available payroll schemes and check service health.
  - name: Health
    description: Service health and readiness checks.
paths:
  /v1/payouts:
    post:
      tags:
        - Payouts
      summary: Create a single payout (mock)
      description: >-
        Create a single-beneficiary payout. The mock provider returns the Payout
        resource and either transitions it through PENDING → PROCESSING → PAID
        asynchronously, or to a deterministic outcome if magic triggers are
        used. **Moves no real money.**
      operationId: Payouts_create_payout
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: Idempotency-Key
        - name: X-Mock-Outcome
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: X-Mock-Outcome
        - name: X-Mock-Outcome-At
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: X-Mock-Outcome-At
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePayoutRequest'
      responses:
        '200':
          description: Idempotent replay — existing payout returned.
          content:
            application/json:
              schema: {}
        '201':
          description: Payout created.
        '400':
          description: Currency mismatch for country.
        '401':
          description: Missing, invalid, revoked or wrong-environment API key.
        '403':
          description: Payouts disabled (PAYOUTS_ENABLED=false).
        '404':
          description: Country not supported.
        '409':
          description: Idempotency or external_id conflict.
        '422':
          description: Validation error (incl. country-specific beneficiary).
        '503':
          description: In-memory store full.
      security:
        - ApiKeyBearer: []
components:
  schemas:
    CreatePayoutRequest:
      properties:
        amount:
          anyOf:
            - type: number
              exclusiveMinimum: 0
            - type: string
              pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Amount
          description: Positive decimal amount.
        currency:
          type: string
          maxLength: 3
          minLength: 3
          title: Currency
          description: ISO 4217 code, uppercase.
        country:
          type: string
          maxLength: 2
          minLength: 2
          title: Country
          description: ISO 3166-1 alpha-2.
        external_id:
          type: string
          maxLength: 80
          minLength: 1
          title: External Id
        description:
          anyOf:
            - type: string
              maxLength: 200
            - type: 'null'
          title: Description
        payment_method_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Payment Method Id
          description: Defaults to the country's default method if omitted.
        beneficiary:
          $ref: '#/components/schemas/Beneficiary'
        payroll_ref:
          anyOf:
            - $ref: '#/components/schemas/PayrollRef'
            - type: 'null'
        notification_url:
          anyOf:
            - type: string
              maxLength: 2083
              minLength: 1
              format: uri
            - type: 'null'
          title: Notification Url
          description: HTTPS only. Receives signed webhook events on every status change.
        metadata:
          additionalProperties: true
          type: object
          title: Metadata
          description: ≤20 keys, string values ≤500 chars.
        processing:
          anyOf:
            - $ref: '#/components/schemas/ProcessingOptions'
            - type: 'null'
      type: object
      required:
        - amount
        - currency
        - country
        - external_id
        - beneficiary
      title: CreatePayoutRequest
      description: Request body for POST /v1/payouts.
    Beneficiary:
      properties:
        name:
          type: string
          maxLength: 200
          minLength: 1
          title: Name
        document_type:
          type: string
          maxLength: 20
          minLength: 2
          title: Document Type
        document_id:
          type: string
          maxLength: 32
          minLength: 1
          title: Document Id
        email:
          anyOf:
            - type: string
            - type: 'null'
          title: Email
        phone:
          anyOf:
            - type: string
            - type: 'null'
          title: Phone
        address:
          anyOf:
            - $ref: '#/components/schemas/Address'
            - type: 'null'
        bank_account:
          additionalProperties: true
          type: object
          title: Bank Account
          description: Per-country shape; validated by CreatePayoutRequest.
      type: object
      required:
        - name
        - document_type
        - document_id
      title: Beneficiary
      description: >-
        Beneficiary fields. Per-country shape is enforced by
        CreatePayoutRequest.


        We keep `bank_account` typed as a generic dict here and do the
        per-country

        discrimination on the parent (where `country` is available). This avoids

        Pydantic's discriminator gotchas and produces cleaner error messages.
    PayrollRef:
      properties:
        calculation_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Calculation Id
        country:
          anyOf:
            - type: string
            - type: 'null'
          title: Country
        scheme:
          anyOf:
            - type: string
            - type: 'null'
          title: Scheme
        year:
          anyOf:
            - type: integer
              maximum: 2100
              minimum: 1900
            - type: 'null'
          title: Year
        concept:
          anyOf:
            - type: string
            - type: 'null'
          title: Concept
          description: Source concept on the payroll result, typically 'net_salary'.
      type: object
      title: PayrollRef
      description: |-
        Free traceability block linking a payout back to a payroll calculation.

        Engine is stateless in v1, so `calculation_id` is informational only.
    ProcessingOptions:
      properties:
        step_seconds:
          anyOf:
            - type: number
              maximum: 60
              minimum: 0
            - type: 'null'
          title: Step Seconds
          description: >-
            Seconds between mock transitions. Clamped to [0, 60]. Set to 0 to
            run the plan synchronously before returning the response — useful
            for tests.
      type: object
      title: ProcessingOptions
      description: Mock-only request knobs that control transition timing.
    Address:
      properties:
        country:
          type: string
          maxLength: 2
          minLength: 2
          title: Country
          description: ISO 3166-1 alpha-2
        state:
          anyOf:
            - type: string
            - type: 'null'
          title: State
        city:
          anyOf:
            - type: string
            - type: 'null'
          title: City
        zip_code:
          anyOf:
            - type: string
            - type: 'null'
          title: Zip Code
        street:
          anyOf:
            - type: string
            - type: 'null'
          title: Street
      type: object
      required:
        - country
      title: Address
  securitySchemes:
    ApiKeyBearer:
      type: http
      description: >-
        API key authentication. Send your API key as: Authorization: Bearer
        <your_api_key>
      scheme: bearer

````