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

# Admin Update Payment Status

> Admin: manually set payment_status (paid / failed / pending).

Marking an offline order (COD / bank transfer) as paid runs the canonical
paid side-effects (commit stock, accrue commission, grant downloads,
order.paid webhook) — mirroring the gateway confirm paths — so COD orders
no longer sit at `pending` forever. Refunds go through POST /refunds, not
here.

VEN-24: only the roles of `staff_permissions.PAYMENT_ROLES` (not the help
desk) → 403 ``order.payment_forbidden``.

ORD-6 (§11.7): «paid» on an order in the trash restores it first (the bank
transfer that arrives late), with the reason mandatory → 422
``order.restore_reason_required``; then, like a gateway payment on an
order in the trash, it goes to Processing (D29), and the stock is taken
for an order that can still be shipped or refunded. Any other payment
status on an order in the trash → 409 ``order.trashed``. Restoring is a
person's act (§10.2): an API token, even with the accountant's role, gets
403 ``auth.api_token_forbidden`` on «paid» for an order in the trash.

An order that WAS in the trash and that the staff restored first (it is
*Cancelled*, with a `restored` row) goes to Processing too when it is
marked paid: from *Cancelled* it could only become *Refunded*, and the
stock taken here would sit on an order that can never be shipped.

ORD-32: «paid» is `lifecycle.mark_order_paid`. On a MANUAL order
(`source='admin'`) with Nextera on, ``fiscal`` (``now`` · ``at_register``
· ``later``) is mandatory → 422 ``order.fiscal_choice_required`` (AZA's
till shares the Nextera key: §9.2); ``now`` with Nextera not usable → 409
``order.fiscal_now_unavailable``, nothing written (never downgraded in
silence to no receipt). A storefront order ignores it and
keeps today's automatic fiscalization. ``delivered_now`` on a manual
order also makes it *Delivered* («Consegnato subito»: paid and picked up
at the counter), 409 ``order.invalid_transition`` if it cannot get there;
a storefront order ignores it too.



## OpenAPI

````yaml https://api.vellaro.io/openapi/admin.json patch /api/v1/admin/orders/{order_id}/payment
openapi: 3.1.0
info:
  title: Vellaro Admin API
  description: >-
    Store management under `/api/v1/admin`, for back ends and integrations.
    Every call takes `Authorization: Bearer <token>`: an admin API token or a
    staff user's token. The permissions of its role decide what it can do,
    always in its own store.
  version: 0.1.0
servers:
  - url: https://api.vellaro.io
    description: Produzione
security: []
tags:
  - name: Orders
    description: >-
      Orders and manual orders, payments, refunds, shipments, invoices, returns,
      customer subscriptions.
  - name: Products
    description: Products, variants, images, prices and discounts, product lookups.
  - name: Categories & catalog setup
    description: >-
      Categories, brands, attributes, options, filters, downloadable files,
      recurring profiles.
  - name: Inventory
    description: Stock of the variants and stock statuses.
  - name: Customers
    description: Customers, customer groups, custom fields.
  - name: Reviews & questions
    description: Moderation of product reviews and questions.
  - name: Promotions & coupons
    description: Coupons and gift vouchers.
  - name: Marketing
    description: Campaigns, newsletter subscribers, affiliates and their commissions.
  - name: Content
    description: >-
      CMS pages, menus, banners, information pages, flipbooks, media library,
      SEO URLs, email templates, translations.
  - name: Settings
    description: >-
      Store settings, email delivery, languages, currencies, physical stores,
      social login providers.
  - name: Shipping
    description: Couriers, shipping rates, weight and length classes.
  - name: Taxes & geo
    description: Tax classes, rates and rules; countries, zones and geo zones.
  - name: Integrations & modules
    description: >-
      Integrations, plugins and modules (Iute, extra warranty, Nextera, Financa
      5, WhatsApp, Firebase), outbound webhooks.
  - name: AI
    description: AI content generation and the settings of the AI shopping assistant.
  - name: Imports
    description: 'CSV imports and the universal import: runs, mappings, previews, undo.'
  - name: Reports & dashboard
    description: Dashboard figures and reports.
  - name: Users & API keys
    description: Staff users and roles, publishable keys, admin API tokens.
  - name: Audit
    description: The store's audit log.
paths:
  /api/v1/admin/orders/{order_id}/payment:
    patch:
      tags:
        - Orders
      summary: Admin Update Payment Status
      description: >-
        Admin: manually set payment_status (paid / failed / pending).


        Marking an offline order (COD / bank transfer) as paid runs the
        canonical

        paid side-effects (commit stock, accrue commission, grant downloads,

        order.paid webhook) — mirroring the gateway confirm paths — so COD
        orders

        no longer sit at `pending` forever. Refunds go through POST /refunds,
        not

        here.


        VEN-24: only the roles of `staff_permissions.PAYMENT_ROLES` (not the
        help

        desk) → 403 ``order.payment_forbidden``.


        ORD-6 (§11.7): «paid» on an order in the trash restores it first (the
        bank

        transfer that arrives late), with the reason mandatory → 422

        ``order.restore_reason_required``; then, like a gateway payment on an

        order in the trash, it goes to Processing (D29), and the stock is taken

        for an order that can still be shipped or refunded. Any other payment

        status on an order in the trash → 409 ``order.trashed``. Restoring is a

        person's act (§10.2): an API token, even with the accountant's role,
        gets

        403 ``auth.api_token_forbidden`` on «paid» for an order in the trash.


        An order that WAS in the trash and that the staff restored first (it is

        *Cancelled*, with a `restored` row) goes to Processing too when it is

        marked paid: from *Cancelled* it could only become *Refunded*, and the

        stock taken here would sit on an order that can never be shipped.


        ORD-32: «paid» is `lifecycle.mark_order_paid`. On a MANUAL order

        (`source='admin'`) with Nextera on, ``fiscal`` (``now`` ·
        ``at_register``

        · ``later``) is mandatory → 422 ``order.fiscal_choice_required`` (AZA's

        till shares the Nextera key: §9.2); ``now`` with Nextera not usable →
        409

        ``order.fiscal_now_unavailable``, nothing written (never downgraded in

        silence to no receipt). A storefront order ignores it and

        keeps today's automatic fiscalization. ``delivered_now`` on a manual

        order also makes it *Delivered* («Consegnato subito»: paid and picked up

        at the counter), 409 ``order.invalid_transition`` if it cannot get
        there;

        a storefront order ignores it too.
      operationId: admin_update_payment_status_api_v1_admin_orders__order_id__payment_patch
      parameters:
        - name: order_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Order Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderPaymentUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse_PaymentSummaryOut_'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    OrderPaymentUpdate:
      properties:
        payment_status:
          type: string
          title: Payment Status
        reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Reason
        notify_customer:
          type: boolean
          title: Notify Customer
          default: false
        fiscal:
          anyOf:
            - type: string
              enum:
                - now
                - at_register
                - later
            - type: 'null'
          title: Fiscal
        delivered_now:
          type: boolean
          title: Delivered Now
          default: false
        iute_amount_verified:
          type: boolean
          title: Iute Amount Verified
          default: false
      type: object
      required:
        - payment_status
      title: OrderPaymentUpdate
      description: 'Admin: manually transition payment_status (paid / failed / pending).'
    ApiResponse_PaymentSummaryOut_:
      properties:
        data:
          anyOf:
            - $ref: '#/components/schemas/PaymentSummaryOut'
            - type: 'null'
        meta:
          anyOf:
            - $ref: '#/components/schemas/PaginationMeta'
            - type: 'null'
        error:
          anyOf:
            - type: string
            - type: 'null'
          title: Error
        error_code:
          anyOf:
            - type: string
            - type: 'null'
          title: Error Code
      type: object
      title: ApiResponse[PaymentSummaryOut]
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    PaymentSummaryOut:
      properties:
        payment_status:
          type: string
          title: Payment Status
        payment_method:
          type: string
          title: Payment Method
        currency:
          type: string
          title: Currency
        total:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Total
        amount_paid:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Amount Paid
        amount_refunded:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Amount Refunded
        net:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Net
        refundable:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Refundable
        voucher_held:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Voucher Held
          default: '0'
        gateway_refs:
          additionalProperties: true
          type: object
          title: Gateway Refs
        transactions:
          items:
            $ref: '#/components/schemas/OrderTransactionOut'
          type: array
          title: Transactions
          default: []
      type: object
      required:
        - payment_status
        - payment_method
        - currency
        - total
        - amount_paid
        - amount_refunded
        - net
        - refundable
        - gateway_refs
      title: PaymentSummaryOut
    PaginationMeta:
      properties:
        page:
          type: integer
          title: Page
        page_size:
          type: integer
          title: Page Size
        total:
          type: integer
          title: Total
        total_pages:
          type: integer
          title: Total Pages
      type: object
      required:
        - page
        - page_size
        - total
        - total_pages
      title: PaginationMeta
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    OrderTransactionOut:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        kind:
          type: string
          title: Kind
        amount:
          type: string
          pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Amount
        currency:
          type: string
          title: Currency
        gateway:
          type: string
          title: Gateway
        gateway_ref:
          anyOf:
            - type: string
            - type: 'null'
          title: Gateway Ref
        status:
          type: string
          title: Status
        is_manual:
          type: boolean
          title: Is Manual
        reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Reason
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
        - id
        - kind
        - amount
        - currency
        - gateway
        - status
        - is_manual
        - created_at
      title: OrderTransactionOut
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.