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

# Order & Checkout Flow (Public)

Create bookings through the public cart and checkout flow. For admin-side creation (`orders/from-config`), see [Admin Booking Creation](/developers/guides/admin/booking-creation).

For conventions, see [JSON-API Conventions](/developers/guides/json-api-conventions). For slot search, see [Availability & Booking Search](/developers/guides/availability).

***

## Prerequisites

* Resource + service configuration exists
* Cookies are enabled (cart and order authorization are cookie/query based)
* Optional customer auth for prefilled fields

***

## Canonical Path Docs

* `/api/v1/order*` cart/checkout endpoints: [../../paths/public/orders.yaml](https://github.com/anny-co/anny-api-docs/blob/main/paths/public/orders.yaml)

***

## Flow Overview

```text theme={null}
1. Add booking(s) to cart
2. Show recommendations in cart
3. Edit cart / voucher
4. Collect checkout data
5. Optional guest email verification
6. Submit checkout
7. Handle payment redirect
8. Fetch last succeeded orders
```

***

<Steps>
  <Step title="Add Booking to Cart">
    ```http theme={null}
    POST /api/v1/order/bookings

    {
      "resource_id": "{resource_id}",
      "service_id": {
        "{service_id}": 1
      },
      "start_date": "2026-04-15T09:00:00+02:00",
      "end_date": "2026-04-15T10:00:00+02:00",
      "add_ons_by_service": {
        "{service_id}": [
          [
            { "add_on_id": "{add_on_id}", "quantity": 2 }
          ]
        ]
      },
      "sub_bookings_by_service": {
        "{service_id}": [
          []
        ]
      }
    }
    ```

    `add_ons_by_service` and `sub_bookings_by_service` are mapped by service id and booking index:

    | Field                                             | Type               | Notes                                                   |
    | ------------------------------------------------- | ------------------ | ------------------------------------------------------- |
    | `service_id`                                      | `string \| object` | Object map (`service_id -> quantity`) is current format |
    | `add_ons_by_service`                              | `object`           | `{service_id: AddOn[][]}`                               |
    | `add_ons_by_service[service_id][booking_index][]` | array item         | `{add_on_id, quantity}`                                 |
    | `sub_bookings_by_service`                         | `object`           | `{service_id: SubBooking[][]}`                          |

    Legacy inputs (`booking_add_ons`, `sub_bookings`) still exist but are deprecated.

    Exact add-booking request fields (current request rules):

    | Field                            | Type                    | Required    | Notes                                               |
    | -------------------------------- | ----------------------- | ----------- | --------------------------------------------------- |
    | `start_date`                     | string (atom date-time) | yes         |                                                     |
    | `end_date`                       | string (atom date-time) | yes         | `>= start_date`                                     |
    | `service_id`                     | string \| int \| object | yes         | object map recommended (`service_id -> quantity`)   |
    | `resource_id`                    | string \| int \| array  | yes         | can be multi-resource                               |
    | `description`                    | string                  | no          | nullable                                            |
    | `customer_note`                  | string                  | no          | nullable                                            |
    | `add_ons_by_service`             | object                  | no          | nullable                                            |
    | `sub_bookings_by_service`        | object                  | no          | nullable                                            |
    | `recurring`                      | object                  | no          | nullable                                            |
    | `recurring.frequency`            | enum                    | no          | `daily`, `weekly`, `monthly`                        |
    | `recurring.duration`             | int                     | conditional | required when `end_date` not used by recurring flow |
    | `recurring.until`                | date                    | no          | nullable                                            |
    | `recurring.interval`             | int                     | no          |                                                     |
    | `recurring.days`                 | array                   | no          |                                                     |
    | `recurring.month_day`            | int                     | no          |                                                     |
    | `recurring.week_start`           | string                  | no          |                                                     |
    | `recurring.set_pos`              | int                     | no          |                                                     |
    | `strategy`                       | enum                    | no          | availability booking strategy                       |
    | `timezone`                       | IANA timezone           | no          |                                                     |
    | `create_sequence`                | boolean                 | no          |                                                     |
    | `timeslot_series_id`             | int                     | no          |                                                     |
    | `original_booking_id`            | string                  | no          |                                                     |
    | `book_on_behalf`                 | string                  | no          | customer account uuid                               |
    | `account_pass`                   | string                  | no          | pass code                                           |
    | `booking_quota_grant_id`         | string \| int \| array  | no          |                                                     |
    | `prevent_applying_default_quota` | boolean                 | no          |                                                     |
    | `adhoc`                          | boolean                 | no          |                                                     |

    Path docs: `/api/v1/order/bookings` in [../../paths/public/orders.yaml](https://github.com/anny-co/anny-api-docs/blob/main/paths/public/orders.yaml).

    Current cart:

    ```http theme={null}
    GET /api/v1/order
    ```
  </Step>

  <Step title="Recommendations in Cart (Before Checkout)">
    Recommendations are a cart-time feature, not a post-order step.

    ```http theme={null}
    GET /api/v1/order/recommendations
    ```
  </Step>

  <Step title="Edit Cart and Voucher">
    Edit add-ons for one booking:

    ```http theme={null}
    POST /api/v1/order/bookings/{booking_id}/edit-addons

    {
      "addons": [
        { "add_on_id": "{add_on_id}", "quantity": 1 }
      ]
    }
    ```

    Remove one booking:

    ```http theme={null}
    DELETE /api/v1/order/bookings/{booking_id}
    ```

    Remove multiple bookings:

    ```http theme={null}
    DELETE /api/v1/order/bookings/delete-multiple

    {
      "filter": {
        "id": ["{booking_id_1}", "{booking_id_2}"]
      }
    }
    ```

    Clear cart:

    ```http theme={null}
    GET /api/v1/order/bookings/delete-all
    ```

    Apply voucher:

    ```http theme={null}
    POST /api/v1/order/voucher

    {
      "code": "SUMMER20"
    }
    ```

    Remove voucher:

    ```http theme={null}
    DELETE /api/v1/order/voucher
    ```

    Optional booking pre-calculation:

    ```http theme={null}
    POST /api/v1/order/bookings/calculate
    ```
  </Step>

  <Step title="Collect Checkout Data">
    Collect the customer data, payment method, and legal document acceptances required for the current organization.

    Public integrations should treat these requirements as organization-defined checkout configuration rather than depending on internal UI helper endpoints.
  </Step>

  <Step title="Optional Guest Email Verification">
    If guest email verification is enabled for the checkout flow, complete that verification before the final order submission.

    The external contract is the `verify_guest_email` field on `POST /api/v1/order`. Helper endpoints used by anny-hosted UIs are internal-only and not part of the external integration surface.
  </Step>

  <Step title="Submit Checkout">
    Customer and address are submitted as separate objects. Keep customer fields under `customer.*` and address fields under
    `address.*`.

    ```http theme={null}
    POST /api/v1/order

    {
      "customer": {
        "email": "jane@example.com",
        "given_name": "Jane",
        "family_name": "Doe"
      },
      "address": {
        "street_address": "123 Main St",
        "address_line_2": "Suite 4B",
        "zip_code": "94105",
        "city": "San Francisco",
        "area": "CA",
        "country_code": "US"
      },
      "payment_method": "{payment_method_slug}",
      "documents": {
        "{legal_doc_uuid}": true
      },
      "verify_guest_email": {
        "state": "{email_verification_state}",
        "code": "123456"
      }
    }
    ```

    Validation depends on the organization's checkout configuration and selected payment method. Address fields returned by
    the form are organization-country aware (for example state/area is only returned where relevant).
  </Step>

  <Step title="Handle Payment Redirect">
    If `meta.payment.next_action.type = redirect`, redirect to `meta.payment.next_action.url`.

    After the payment provider redirects the user back, proceed to Step 8 to fetch the completed order.
  </Step>

  <Step title="Fetch Last Succeeded Orders">
    `last-succeeded` authorization is token-pair based and requires matching `oids[]` and `oats[]` arrays.

    ```http theme={null}
    GET /api/v1/order/last-succeeded?oids[]={order_id_1}&oats[]={access_token_1}&oids[]={order_id_2}&oats[]={access_token_2}
    ```
  </Step>
</Steps>

***

## Common Errors

| Error                            | Cause                                         | Solution                                                     |
| -------------------------------- | --------------------------------------------- | ------------------------------------------------------------ |
| `422` add-ons ignored or invalid | Wrong `add_ons_by_service` shape              | Use `service_id -> booking_index -> [{add_on_id, quantity}]` |
| `422` slot unavailable           | Race condition between selection and checkout | Re-check availability and re-add booking                     |
| `409` order already completed    | Duplicate checkout submit                     | Block duplicate submit and refresh cart state                |
| `422` verification code invalid  | Wrong/expired guest email code                | Request a new code                                           |
