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

# Create an order

> Creates an order and initialises a Paystack payment session.

The response includes:
- `order` — a summary of the created order.
- `payment.payment_link` — the Paystack checkout URL to redirect the customer to.

**Delivery modes** (`fulfilment_method`):
| Value | Meaning |
|---|---|
| `pickup` | Customer collects from the store |
| `delivery` | Manual or ShipBubble delivery |

For manual delivery, pass `manual_delivery_option` (UID of a `StoreDeliveryOptions` record from `GET /delivery-options`).

For ShipBubble delivery, pass `courier` and `rate` from `POST /shipping-quotes`.

All item variants must belong to the authenticated store.



## OpenAPI

````yaml /LeyyowPublicAPI(v2).yaml post /orders
openapi: 3.0.3
info:
  title: Leyyow Public API
  version: 1.0.0 (v2)
  description: >-
    The Leyyow Public API lets you build custom storefronts on top of any Leyyow
    merchant store.


    ## Authentication


    Every request must carry a merchant API key as a Bearer token:


    ```

    Authorization: Bearer lyw_<your-secret-key>

    ```


    Keys are scoped to a single store.  All responses contain only data that
    belongs to the store that issued the key.


    ## Rate limits


    | Throttle group | Limit |

    |---|---|

    | Catalogue endpoints (per key) | 1 000 / hour |

    | Catalogue endpoints (per IP) | 200 / hour |

    | Order creation (per key) | 50 / hour |

    | Shipping quotes (per key) | 100 / hour |


    When a limit is exceeded the API returns HTTP 429 with a `Retry-After`
    header indicating how many seconds to wait.


    ## Store scoping


    The `X-Store-Id` header is ignored.  Store identity is derived entirely from
    the API key — there is no way to access a different store's data using the
    same key.
servers:
  - url: /api/public/v1
    description: Leyyow Public API v1
security: []
paths:
  /orders:
    post:
      tags:
        - Orders
      summary: Create an order
      description: >-
        Creates an order and initialises a Paystack payment session.


        The response includes:

        - `order` — a summary of the created order.

        - `payment.payment_link` — the Paystack checkout URL to redirect the
        customer to.


        **Delivery modes** (`fulfilment_method`):

        | Value | Meaning |

        |---|---|

        | `pickup` | Customer collects from the store |

        | `delivery` | Manual or ShipBubble delivery |


        For manual delivery, pass `manual_delivery_option` (UID of a
        `StoreDeliveryOptions` record from `GET /delivery-options`).


        For ShipBubble delivery, pass `courier` and `rate` from `POST
        /shipping-quotes`.


        All item variants must belong to the authenticated store.
      operationId: orders_create
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicAPIOrderCreate'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PublicAPIOrderCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/PublicAPIOrderCreate'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderCreateResponse'
              examples:
                OrderCreated:
                  value:
                    order:
                      uid: 018e1234-0000-7000-a000-000000000100
                      order_number: RB-20250115-0043
                      payment_status: unpaid
                      total_amount: '17500.00'
                      created_at: '2025-01-15T10:35:00Z'
                    payment:
                      payment_link: https://checkout.paystack.com/7f3k9xp2abc
                  summary: Order created
          description: Order created and payment initialised.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/_Error'
              examples:
                ValidationError:
                  value:
                    detail:
                      items:
                        - One or more variants do not belong to this store.
                  summary: Validation error
          description: Validation error — see `detail` for field-level errors.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/_Error'
              examples:
                InvalidKey:
                  value:
                    detail: Invalid or revoked API key.
                    error_code: AUTHENTICATION_FAILED
                  summary: Invalid key
          description: Authentication failed — key missing, invalid, or revoked.
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/_Error'
              examples:
                RateLimited:
                  value:
                    detail: Rate limit exceeded. Please retry in 120 seconds.
                    error_code: ENDPOINT_THROTTLED
                  summary: Rate limited
          description: >-
            Rate limit exceeded.  Retry after the number of seconds indicated in
            the `Retry-After` response header.


            | Throttle group | Limit |

            |---|---|

            | Catalogue endpoints — per API key | 1 000 / hour |

            | Catalogue endpoints — per IP address | 200 / hour |

            | Order creation — per API key | 50 / hour |

            | Shipping quotes — per API key | 100 / hour |
      security:
        - MerchantAPIKey: []
components:
  schemas:
    PublicAPIOrderCreate:
      type: object
      description: |-
        Extends the storefront order serializer for the public API.

        The only addition is store-scoped variant validation: every item variant
        must belong to the authenticated store. All other logic (pricing, stock,
        delivery, coupon, Paystack init) is inherited unchanged.
      properties:
        customer_name:
          type: string
          writeOnly: true
        customer_email:
          type: string
          format: email
          writeOnly: true
        customer_phone:
          type: string
          writeOnly: true
        items:
          type: array
          items:
            $ref: '#/components/schemas/PublicOrderItem'
          writeOnly: true
        delivery_address:
          type: string
          nullable: true
        delivery_method:
          type: string
          nullable: true
        manual_delivery_option:
          type: string
          format: uuid
          nullable: true
          description: Manual delivery option for this order
        fulfilment_method:
          type: string
          default: pickup
        payment_source:
          $ref: '#/components/schemas/PaymentSourceEnum'
        courier: {}
        rate:
          type: string
          maxLength: 100
        cart:
          type: string
          format: uuid
          nullable: true
          description: Cart this order came from (one cart, one order)
        note:
          type: string
          description: Optional note; stored on the order (not as a memo).
        coupon_code:
          type: string
          writeOnly: true
          maxLength: 50
      required:
        - customer_email
        - customer_name
        - items
        - payment_source
    OrderCreateResponse:
      type: object
      properties:
        order:
          $ref: '#/components/schemas/OrderCreateSummary'
        payment:
          $ref: '#/components/schemas/OrderCreatePayment'
      required:
        - order
        - payment
    _Error:
      type: object
      properties:
        detail:
          type: string
        error_code:
          type: string
      required:
        - detail
    PublicOrderItem:
      type: object
      description: Serializer for public order items
      properties:
        uid:
          type: string
          format: uuid
          readOnly: true
        variant:
          type: string
          format: uuid
          nullable: true
        variant_name:
          type: string
          readOnly: true
        variant_sku:
          type: string
          readOnly: true
        product_name:
          type: string
          readOnly: true
        popup_inventory:
          type: string
          format: uuid
          writeOnly: true
          nullable: true
        quantity:
          type: integer
          maximum: 2147483647
          minimum: 0
        original_price:
          type: string
          format: decimal
          pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
          nullable: true
          description: Variant's regular price at time of order creation
        unit_price:
          type: string
          format: decimal
          pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
          readOnly: true
        total_price:
          type: string
          format: decimal
          pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
          readOnly: true
          description: >-
            Total price of the item; it could also be the discounted or
            promotional price
        discount_amount:
          type: string
          format: decimal
          pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
          description: >-
            Coupon discount applied to this item (only set for
            product/category-scoped coupons)
        total_cost:
          type: string
          format: decimal
          pattern: ^-?\d{0,10}(?:\.\d{0,2})?$
          description: Total inventory cost captured at reservation time
        fulfilment_status:
          allOf:
            - $ref: '#/components/schemas/FulfilmentStatusE48Enum'
          readOnly: true
          description: |-
            Fulfilment status of this item

            * `unfulfilled` - Unfulfilled
            * `fulfilled` - Fulfilled
            * `returned` - Returned
            * `partially_fulfilled` - Partially Fulfilled
        qty_fulfilled:
          type: integer
          readOnly: true
        notes:
          type: string
          description: Customer notes for this item (e.g., 'No onions', 'Extra sauce')
        attributes:
          type: string
          readOnly: true
        product_images:
          type: string
          readOnly: true
      required:
        - attributes
        - fulfilment_status
        - product_images
        - product_name
        - qty_fulfilled
        - total_price
        - uid
        - unit_price
        - variant_name
        - variant_sku
    PaymentSourceEnum:
      enum:
        - paystack
      type: string
      description: '* `paystack` - paystack'
    OrderCreateSummary:
      type: object
      properties:
        uid:
          type: string
          format: uuid
        order_number:
          type: string
        payment_status:
          type: string
        total_amount:
          type: string
          format: decimal
          pattern: ^-?\d{0,10}(?:\.\d{0,2})?$
        created_at:
          type: string
          format: date-time
      required:
        - created_at
        - order_number
        - payment_status
        - total_amount
        - uid
    OrderCreatePayment:
      type: object
      properties:
        payment_link:
          type: string
          format: uri
          description: Paystack checkout URL — redirect the customer here.
      required:
        - payment_link
    FulfilmentStatusE48Enum:
      enum:
        - unfulfilled
        - fulfilled
        - returned
        - partially_fulfilled
      type: string
      description: |-
        * `unfulfilled` - Unfulfilled
        * `fulfilled` - Fulfilled
        * `returned` - Returned
        * `partially_fulfilled` - Partially Fulfilled
  securitySchemes:
    MerchantAPIKey:
      type: http
      scheme: bearer
      bearerFormat: lyw_<secret>
      description: >-
        Authenticate using a Leyyow merchant API key.


        Include the key in every request as a Bearer token:


        ```

        Authorization: Bearer lyw_<your-secret-key>

        ```


        Keys are scoped to a single store. All endpoints return data belonging
        to the store that issued the key — there is no `X-Store-Id` override.


        Keys are created in the Leyyow merchant dashboard under **Settings →
        Developer → API Keys**.

````