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

# Update additional fee

> Sets your own charge (a delivery fee, handling, or similar) on top of one of your **standard** escrows. Every escrow starts at `additionalFee: 0`.

The buyer is charged `amount + their fee share + additionalFee` at checkout, and the whole `additionalFee` is credited to **your merchant wallet** when the escrow completes, recorded as a `delivery` transaction so it stays separate from your commission. Payluk takes no cut of it, and it is not part of the escrow amount, so neither the seller's payout nor the escrow `fee` changes.

### When you can call this

Only while the escrow is still `PENDING` / `AWAITING_PAYMENT`. Once the buyer pays, the charge is frozen, because they have already been quoted and debited a total that includes it. It is a plain setter until then: call it as often as you need, and send `0` to remove a charge you set earlier.

Standard escrows only. Milestone and vault escrows are rejected.

### Refunds

Who keeps the charge if a dispute is later resolved in the buyer's favour is normally decided **when you resolve that dispute**: [Resolve dispute](/api-reference/disputes/resolve-dispute) takes `additionalFeeRefundable` with your ruling, since only then do you know whether the delivery happened.

Sending `additionalFeeRefundable` here just sets the default that applies if a dispute is resolved without an explicit choice: `true` (the default) returns the charge to the buyer, `false` credits it to you. Omit the field to leave the escrow's current setting untouched.

**Super-admin key required.** Do **not** send the `customer-id` header.



## OpenAPI

````yaml openapi.json PUT /v1/escrow/additional-fee/{paymentToken}
openapi: 3.0.3
info:
  title: Payluk ThirdParty API
  version: 1.0.0
  description: >-
    Merchant / Business API for the Payluk escrow and payments platform.


    All routes are mounted under `/v1` and authenticated with a secret key.
    Every response uses the standard envelope `{ status, message, data }`.
  contact:
    name: Payluk Developer Support
    email: support@payluk.ng
    url: https://payluk.ng
servers:
  - url: https://staging.api.payluk.ng
    description: 'Staging: use sk_test_ keys here for safe testing'
  - url: https://api.payluk.ng
    description: 'Production: use sk_live_ keys'
security:
  - bearerAuth: []
tags:
  - name: Escrow
    description: Create and manage standard escrow payment links.
  - name: Milestone Escrow
    description: Escrows that release funds in parts as milestones are confirmed.
  - name: Vault Escrow
    description: >-
      Merchant-only pooled-stake escrows: customers stake from their wallets and
      the merchant declares the winner.
  - name: Categories
    description: Organise escrows into merchant-defined categories.
  - name: Merchant Customers
    description: Manage the buyers and sellers that transact under your merchant account.
  - name: Disputes
    description: Confirm deliveries, raise disputes and resolve them.
  - name: Payments
    description: Fund wallets and escrows, verify references and manage payout details.
  - name: Debit Cards
    description: List and remove customers' saved debit cards.
  - name: Crypto Whitelist
    description: Manage whitelisted crypto withdrawal addresses.
  - name: Misc
    description: Supporting reference data.
paths:
  /v1/escrow/additional-fee/{paymentToken}:
    put:
      tags:
        - Escrow
      summary: Update additional fee
      description: >-
        Sets your own charge (a delivery fee, handling, or similar) on top of
        one of your **standard** escrows. Every escrow starts at `additionalFee:
        0`.


        The buyer is charged `amount + their fee share + additionalFee` at
        checkout, and the whole `additionalFee` is credited to **your merchant
        wallet** when the escrow completes, recorded as a `delivery` transaction
        so it stays separate from your commission. Payluk takes no cut of it,
        and it is not part of the escrow amount, so neither the seller's payout
        nor the escrow `fee` changes.


        ### When you can call this


        Only while the escrow is still `PENDING` / `AWAITING_PAYMENT`. Once the
        buyer pays, the charge is frozen, because they have already been quoted
        and debited a total that includes it. It is a plain setter until then:
        call it as often as you need, and send `0` to remove a charge you set
        earlier.


        Standard escrows only. Milestone and vault escrows are rejected.


        ### Refunds


        Who keeps the charge if a dispute is later resolved in the buyer's
        favour is normally decided **when you resolve that dispute**: [Resolve
        dispute](/api-reference/disputes/resolve-dispute) takes
        `additionalFeeRefundable` with your ruling, since only then do you know
        whether the delivery happened.


        Sending `additionalFeeRefundable` here just sets the default that
        applies if a dispute is resolved without an explicit choice: `true` (the
        default) returns the charge to the buyer, `false` credits it to you.
        Omit the field to leave the escrow's current setting untouched.


        **Super-admin key required.** Do **not** send the `customer-id` header.
      operationId: updateAdditionalFee
      parameters:
        - $ref: '#/components/parameters/PaymentToken'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAdditionalFeeInput'
            examples:
              setFee:
                summary: Set a delivery fee
                value:
                  additionalFee: 2500
              nonRefundable:
                summary: Set a fee you keep even if the order is refunded
                value:
                  additionalFee: 2500
                  additionalFeeRefundable: false
              clearFee:
                summary: Remove the fee
                value:
                  additionalFee: 0
      responses:
        '200':
          description: Additional fee updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EscrowResponse'
              example:
                status: 200
                message: Additional fee updated successfully
                data:
                  id: 665f1b2c9a1e4d0012ab3c10
                  amount: 150000
                  fee: 3750
                  additionalFee: 2500
                  additionalFeeRefundable: true
                  paymentToken: PY_8AB12C9D3045
                  state: AWAITING_PAYMENT
                  status: PENDING
                  settlementType: STANDARD
                  updatedAt: '2026-08-11T10:20:00.000Z'
        '400':
          description: >-
            Invalid amount, wrong escrow type, already funded, or not your
            escrow.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                alreadyPaid:
                  summary: Already funded
                  value:
                    status: 400
                    message: >-
                      An additional fee can only be updated while the escrow is
                      pending payment
                    data: {}
                notStandard:
                  summary: Not a standard escrow
                  value:
                    status: 400
                    message: An additional fee can only be set on a standard escrow
                    data: {}
                notOwner:
                  summary: Another merchant's escrow
                  value:
                    status: 400
                    message: Escrow does not belong to this merchant
                    data: {}
                noMerchant:
                  summary: Escrow has no merchant
                  value:
                    status: 400
                    message: Escrow is not associated with any merchant
                    data: {}
                notFound:
                  summary: Unknown token
                  value:
                    status: 400
                    message: Escrow not found
                    data: {}
                negative:
                  summary: Negative amount
                  value:
                    status: 400
                    message: additionalFee cannot be negative
                    data: {}
                customerIdSent:
                  summary: customer-id header sent
                  value:
                    status: 400
                    message: customer-id is not allowed in request header
                    data: {}
        '401':
          $ref: '#/components/responses/AccessDenied'
components:
  parameters:
    PaymentToken:
      name: paymentToken
      in: path
      required: true
      description: The escrow's payment token (e.g. `PY_8AB12C9D3045`).
      schema:
        type: string
      example: PY_8AB12C9D3045
  schemas:
    UpdateAdditionalFeeInput:
      type: object
      required:
        - additionalFee
      properties:
        additionalFee:
          type: integer
          minimum: 0
          description: >-
            The charge to add on top of the escrow amount, as a whole number in
            NGN. Send `0` to remove a charge set earlier.
          example: 2500
        additionalFeeRefundable:
          type: boolean
          default: true
          description: >-
            The **default** for who keeps the charge if a dispute is resolved in
            the buyer's favour: `true` returns it to the buyer, `false` credits
            it to you. Usually left alone, since the decision is normally made
            when resolving the dispute, which overrides this. Omit to leave the
            escrow's current setting unchanged.
          example: true
    EscrowResponse:
      type: object
      properties:
        status:
          type: integer
          example: 200
        message:
          type: string
          example: Operation successful
        data:
          $ref: '#/components/schemas/Escrow'
    ApiError:
      type: object
      description: Standard error envelope.
      properties:
        status:
          type: integer
          example: 400
        message:
          type: string
          example: Action not allowed
        data:
          type: object
          example: {}
    Escrow:
      type: object
      properties:
        id:
          type: string
          example: 665f1b2c9a1e4d0012ab3c10
        amount:
          type: integer
          example: 150000
        purpose:
          type: string
          example: MacBook Pro 14"
        description:
          type: string
          example: Space grey, sealed
        whoPays:
          type: string
          enum:
            - buyer
            - seller
            - both
          example: both
        imageUrl:
          type: array
          items:
            type: string
          example:
            - https://cdn.payluk.ng/escrow/abc.png
        fee:
          type: integer
          example: 3750
        additionalFee:
          type: integer
          description: >-
            The merchant's own charge on top of the amount (delivery and the
            like). 0 unless set through Update additional fee.
          example: 0
        additionalFeeRefundable:
          type: boolean
          description: >-
            Whether a buyer-favoured dispute refund returns the additional fee
            to the buyer.
          example: true
        paymentToken:
          type: string
          example: PY_8AB12C9D3045
        paidAt:
          type: string
          nullable: true
          example: null
        status:
          $ref: '#/components/schemas/EscrowStatus'
        state:
          $ref: '#/components/schemas/EscrowState'
        channel:
          type: string
          example: API
        isSeller:
          type: boolean
          example: true
        dispute:
          type: array
          nullable: true
          items:
            type: object
          example: null
        category:
          type: object
          nullable: true
          example: null
        completedAt:
          type: string
          nullable: true
          example: null
        maxDelivery:
          type: integer
          example: 3
        deliveryTimeline:
          type: string
          example: days
        totalQuantity:
          type: integer
          example: 1
        settlementType:
          $ref: '#/components/schemas/SettlementType'
        milestones:
          type: array
          items:
            $ref: '#/components/schemas/Milestone'
        participants:
          type: array
          nullable: true
          description: 'VAULT escrows only: the customers staking into the pot.'
          items:
            $ref: '#/components/schemas/VaultParticipant'
        winnerId:
          type: string
          nullable: true
          description: >-
            VAULT escrows only: the participant declared the winner by the
            merchant.
          example: null
        createdAt:
          type: string
          example: '2026-06-22T10:15:00.000Z'
        updatedAt:
          type: string
          example: '2026-06-22T10:15:00.000Z'
    EscrowStatus:
      type: string
      description: High-level escrow status.
      enum:
        - PENDING
        - ONGOING
        - COMPLETED
        - REFUNDED
        - CLAIMED
        - DISPUTED
        - INVESTIGATING
    EscrowState:
      type: string
      description: Lifecycle state of the escrow.
      enum:
        - AWAITING_PAYMENT
        - OPENED
        - CLOSED
    SettlementType:
      type: string
      enum:
        - STANDARD
        - MILESTONE
        - VAULT
    Milestone:
      type: object
      properties:
        id:
          type: string
          example: 665f1b2c9a1e4d0012ab3c21
        title:
          type: string
          example: Design
        description:
          type: string
          example: Figma mockups
        amount:
          type: integer
          example: 300000
        dueDate:
          type: string
          nullable: true
          example: '2026-07-15'
        customerId:
          type: string
          nullable: true
          description: >-
            Optional beneficiary. When set, releasing this milestone credits
            this customer's main balance instead of the seller's.
          example: null
        status:
          type: string
          enum:
            - PENDING
            - RELEASED
          example: PENDING
        releasedAt:
          type: string
          nullable: true
          example: null
    VaultParticipant:
      type: object
      properties:
        customerId:
          type: string
          example: 665f1b2c9a1e4d0012ab3c40
        amount:
          type: integer
          example: 600000
        status:
          type: string
          enum:
            - STAKED
            - RELEASED
            - REFUNDED
          example: STAKED
        stakedAt:
          type: string
          description: Unix timestamp (seconds) the stake was locked.
          example: '1784900000'
        settledAt:
          type: string
          nullable: true
          description: Unix timestamp (seconds) the stake was released or refunded.
          example: null
  responses:
    AccessDenied:
      description: Access denied.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            status: 401
            message: Access denied
            data: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your secret key as a Bearer token. The key prefix selects the
        environment: `sk_test_...` (test) or `sk_live_...` (live).

````