Learn how to create and manage order fulfillment using the Square Orders API.
Orders API

Manage Order Fulfillments

A seller can optionally add fulfillment information to an order when it is created or after it is created. Sellers can use Square products or custom applications using the Orders API to manage fulfillments.

The Orders API supports creating and managing fulfillments of these types:

  • SHIPMENT

  • PICKUP

  • DELIVERY (beta)

    Note

    This is a closed beta. Request beta access by completing our participation survey.

Beta access to the DELIVERY fulfillment type is for use cases other than performing deliveries on behalf of sellers. Developers seeking to perform deliveries on behalf of sellers need a formal partnership agreement. To become an app partner, submit a partnership request. !!!

An order can have one or more fulfillments, as described in the following examples:

  • Suppose a customer in a gardening store buys flowers and a large bag of dirt. The customer takes the flowers immediately but chooses to pick up the dirt later in the day. In this case, the seller creates two fulfillments of the PICKUP type.

  • Suppose a customer orders a shirt and two pairs of shoes (brown shoes and black shoes). Now suppose the brown shoes are not in stock. The seller might then choose to ship the brown shoes at a later date. In this case, the order has two fulfillments.

Note that, if an order has multiple fulfillments, they must be of the same fulfillment type.

The Orders API stores fulfillment information in the Order.fulfillments field (an array of Fulfillment objects). Each Fulfillment includes:

  • uid. A Square-assigned unique identifier.

  • type. The type of fulfillment.

  • state. Initially, the fulfillment state is PROPOSED.

  • Fulfillment details. Depending on the type, fulfillment details are stored in pickup_details, shipment_details, and delivery_details.

The following Order fragment shows a single fulfillment (see Fulfillment) of the SHIPMENT type:

The recipient.display_name is the only shipment_details field required at the time of creating a fulfillment. The following apply for the other shipment_details fields:

  • Applications can provide other optional shipment_details (either at the time of creating a fulfillment or later using UpdateOrder) such as carrier, shipping_note, shipping_type, tracking_number, and tracking_url.

  • Some of the timestamp fields are automatically set as the order fulfillment state changes. For example:

    • The packaged_at timestamp is set when the fulfillment state changes to PREPARED.

    • The shipped_at timestamp is set when the fulfillment state changes to COMPLETED.

    • The canceled_at timestamp is set when the fulfillment state changes to CANCELED.

    • The failed_at timestamp is set when the fulfillment state changes to FAILED.

    • The in_progress_at timestamp is set when the fulfillment state changes to RESERVED.

The following Order fragment shows a single fulfillment (see Fulfillment) of the PICKUP type:

The pickup_at and recipient.display_name fields are the only pickup_details fields required at the time of creating a fulfillment. The following apply for the other pickup_details fields:

  • The schedule_type value determines the following:

    • If set to SCHEDULED, pick_up_at is required.

    • If set to ASAP, prep_time_duration is required.

  • These fields can only be set while the order fulfillment state is PROPOSED: expires_at, auto_complete_duration, prep_time_duration, and schedule_type.

  • Some of the timestamp fields are automatically set as the order fulfillment state changes. For example:

    • The accepted_at timestamp is set when the fulfillment state changes to RESERVED.

    • The ready_at timestamp is set when the fulfillment state changes to PREPARED.

    • The pick_up_at timestamp is set when the fulfillment state changes to COMPLETED.

    • The canceled_at timestamp is set when the fulfillment state changes to CANCELED.

    • The rejected_at timestamp is set when the fulfillment state changes to FAILED.

The following Order fragment shows a DELIVERY type fulfillment:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
{
   "order":{
      "id":"MgVVrx8GhOy4K7LO7LtYwgM3RUaZY",
      "location_id":"7WQ0KXC8ZSD90",
      "line_items":[
         {
           ...
         }
      ],
      "fulfillments":[
         {
            "uid":"uYJmomsp8OjA2iY8PZR2IC",
            "type":"DELIVERY",
            "state":"PROPOSED",
            "delivery_details":{
               "recipient":{
                  "display_name":"John Doe",
                  "phone_number":"2065129261",
                  "address":{
                     "address_line_1":"111 Maple",
                     "locality":"Seattle"
                  }
               },
               "deliver_at":"2022-05-25T20:59:33.123Z"
            }
         }
      ]
      ...
      "state":"OPEN",
      "version":1,
      ...
   }
}

Note the following about delivery_details:

  • The following information is required at the time of creating a delivery fulfillment:

    • recipient details. The display_name, address, and phone_number are required, if there is no third-party managing delivery (managed_delivery is set to false).

    • schedule_type. It can be set to SCHEDULED (default) or ASAP.

    • deliver_at. If schedule_type is set to ASAP, this field is automatically set to the time the order is created plus the prep_time_duration. This field is required when schedule_type is set to SCHEDULED.

  • Applications can provide optional delivery_detail information, such as:

    • prep_time_duration. The time it takes to prepare and deliver the fulfillment.

    • A combination of deliver_at and delivery_window_duration identifying the order delivery window.

    • Courier information such as courier_provider_name, courier_support_phone_number, and the combination of courier_pickup_at and courier_pickup_window_duration identifying the courier pickup window.

    • Other information such as optional drop-off notes and whether the delivery is a no-contact delivery.

  • For a delivery managed by a third party:

    • Set the managed_delivery field to true. This makes the recipient information optional, such as display_name and address.

    • The courier_provider_name and courier_support_phone_number fields are required.

  • Some of the timestamp fields are automatically set as the order fulfillment state changes. For example:

    • The delivery_details.in_progress_at timestamp is set when the fulfillment state changes to RESERVED.

    • The delivery_details.canceled_at timestamp is set when the fulfillment state changes to CANCELED.

    • The delivery_details.rejected_at timestamp is set when the fulfillment state changes to FAILED.

    • The delivery_details.ready_at timestamp is set when the fulfillment state changes to PREPARED.

    • The delivery_details.completed_at timestamp is set when the fulfillment state changes to COMPLETED.

  • Orders with fulfillments appear on Square products (such as the Seller Dashboard and Point of Sale application) only after they are paid for. Sellers can then manage fulfillments for these orders using these Square products.

  • Developers can add only one fulfillment to an order using the Orders API, either during or after creation.

    The Orders API does not support splitting a fulfillment. A seller can optionally split a fulfillment using Square products and applications can view these split fulfillments. For example, the Order.fulfillments object includes two fields (entries and line_item_application) that applications can use to determine which line items belong to which fulfillment.

  • Some fulfillment fields can be updated based on the fulfillment state. Some fulfillment fields are immutable. In general, developers can use the Orders API to apply limited fulfillment updates, such as:

    • Updating the state (if the order is being managed through a developer's application rather than Square Order Manager).

    • Updating pickup details such as the pickup_at or note field.

    • Updating recipient details such as address or phone_number.

    • Updating shipment details such as tracking_number or tracking_url.

  • Applications can use the Orders API to create a fulfillment of the SHIPMENT, PICKUP, and DELIVERY types.

    Currently, only Square Online supports creating fulfillments of the DELIVERY type; other Square products (such as the Seller Dashboard and Point of Sale) do not. When applications retrieve an order using the Orders API, they see the DELIVERY type fulfillment but they do not see other delivery details of the fulfillment.

  • All fulfillments in an order are the same type. When a seller splits a fulfillment, both fulfillments are of the same type. To change the fulfillment type, you must first move the fulfillment to the CANCELED state and then add another fulfillment of the type you want.

Applications can create an order with fulfillment or first create an order and later update the order to include fulfillment.

This example is a CreateOrder request that creates an order for four sandwiches. The order includes fulfillment details. The order type is a PICKUP order and the customer, John Doe, has selected curbside pickup at a specific time.

Create Order
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
curl https://connect.squareupsandbox.com/v2/orders \
  -X POST \
  -H 'Square-Version: 2023-01-19' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_KEY}",
    "order": {
      "location_id": "{LOCATION_ID}",
      "line_items": [
        {
          "name": "Sandwich",
          "note": "adhoc item",
          "base_price_money": {
            "amount": 1500,
            "currency": "USD"
          },
          "quantity": "4"
        }
      ],
      "fulfillments": [
        {
          "pickup_details": {
            "is_curbside_pickup": true,
            "pickup_at": "2022-02-12T23:00:00.000Z",
            "recipient": {
              "display_name": "John Doe",
              "phone_number": "111-111-1111"
            }
          },
          "type": "PICKUP"
        }
      ]
    }
  }'

The following is an example response fragment:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
{
  "order": {
    "id": "sfADX2Xqb8F4uZaFuAp3xlShefbZY",
    "location_id": "S8GWD5R9QB376",
    "line_items": [
      {
        "uid": "U0PzEdJgoOPWE7AxvCRldC",
        "quantity": "4",
        "name": "Sandwich",
        "base_price_money": {
          "amount": 1500,
          "currency": "USD"
        },
        "note": "adhoc item",
        "gross_sales_money": {
          "amount": 6000,
          "currency": "USD"
        },
    …
    ],
    "fulfillments": [
      {
        "uid": "VnDwb1Yu42mMjrPEWHLYW",
        "type": "PICKUP",
        "state": "PROPOSED",
        "pickup_details": {
          "pickup_at": "2022-02-12T23:00:00.000Z",
          "recipient": {
            "display_name": "John Doe",
            "phone_number": "111-111-1111"
          },
          "is_curbside_pickup": true
        }
      }
    ],
 …
  }
}

In this example, you first create an order and then update the order to add fulfillment. Note that you cannot add a fulfillment if the order state is COMPLETED.

  1. Call CreateOrder to create an order without a fulfillment.

    Create Order
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    curl https://connect.squareupsandbox.com/v2/orders \
      -X POST \
      -H 'Square-Version: 2023-01-19' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json' \
      -d '{
        "idempotency_key": "{UNIQUE_KEY}",
        "order": {
          "location_id": "{LOCATION_ID}",
          "line_items": [
            {
              "name": "Sandwich",
              "note": "adhoc item",
              "base_price_money": {
                "amount": 1500,
                "currency": "USD"
              },
              "quantity": "4"
            }
          ]
        }
      }'
  2. Call UpdateOrder to update the order and add fulfillment details. The example adds the PICKUP type fulfillment to the order.

    Update Order
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    curl https://connect.squareupsandbox.com/v2/orders/{order_id} \
      -X PUT \
      -H 'Square-Version: 2023-01-19' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json' \
      -d '{
        "idempotency_key": "{UNIQUE_KEY}",
        "order": {
          "location_id": "{LOCATION_ID}",
          "fulfillments": [
            {
              "type": "PICKUP",
              "pickup_details": {
                "is_curbside_pickup": true,
                "pickup_at": "2022-02-12T23:00:00.000Z",
                "recipient": {
                  "phone_number": "111-111-1111",
                  "display_name": "John Doe"
                }
              }
            }
          ],
          "version": 1
        }
      }'

Note

To view the fulfillments for an existing order, call RetrieveOrder. The fulfillments appear in the Order.fulfillments object of the RetrieveOrder response.

In the current implementation, there are limitations to updating fulfillments using the Orders API. For more information, see Guidelines and limitations.

Suppose you created an order for an ad hoc item. The following UpdateOrder example updates the fulfillment state, recipient display name, pickup detail note, and recipient display name:

Update Order
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
curl https://connect.squareupsandbox.com/v2/orders/{order_id} \
  -X PUT \
  -H 'Square-Version: 2023-01-19' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_KEY}",
    "order": {
      "fulfillments": [
        {
          "state": "PREPARED",
          "pickup_details": {
            "note": "updated note",
            "recipient": {
              "display_name": "Jane Doe"
            }
          },
          "uid": "VnDwb1Yu42mMjrPEWHLYW"
        }
      ],
      "version": 1
    }
  }'

The following is an example response fragment:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
{
  "order": {
    "id": "sfADX2Xqb8F4uZaFuAp3xlShefbZY",
    "location_id": "S8GWD5R9QB376",
    "line_items": [
      {
        …
      }
    ],
    "fulfillments": [
      {
        "uid": "VnDwb1Yu42mMjrPEWHLYW",
        "type": "PICKUP",
        "state": "PREPARED",
        "pickup_details": {
          "pickup_at": "2022-02-12T23:00:00.000Z",
          "note": "updated note",
          "accepted_at": "2022-02-26T00:24:07.316Z",
          "ready_at": "2022-02-26T00:24:07.316Z",
          "recipient": {
            "display_name": "Jane Doe",
            "phone_number": "111-111-1111"
          },
          "is_curbside_pickup": true
        }
      }
    ],
    …
    "version": 2,
  }
}

A DELIVERY type fulfillment completes when the items are delivered to the buyer. However, there are times when a seller (or deliver service) cancels the fulfillment or the fulfillment fails to complete. The following are the suggested best practices for an application to update an order as the DELIVERY type fulfillment progresses:

  • Fulfillment completes successfully:

    • If the fulfillment.state is not COMPLETED:

      • Set FulfillmentDeliveryDetails.delivered_at to the timestamp when delivery occurred.

      • Set fulfillment.state to COMPLETED.

      • Set order.state to COMPLETED, if no other fulfillments are pending.

    • If the fulfillment.state is COMPLETED (this can happen if a seller marks it as COMPLETED after they hand off the goods to the delivery service but before the delivery is completed):

      • The application can update delivered_at after a fulfillment is marked as COMPLETED but before the order state is COMPLETED. If deliver_at cannot be updated, the application might save the delivered_at timestamp as a note in the order.fulfillments.delivery_details.note field.

      • Set order.state to COMPLETED, if no other fulfillments are pending.

  • The seller or delivery service cancels the fulfillment:

    • Specify the cancellation reason in the FulfillmentDeliveryDetails.notes field.

    • Set order.state to COMPLETED, if no other fulfillments are pending.

    • Set order.state to COMPLETED or CANCELED. Note that, you cannot set order state to CANCELED if:

      • A completed payment exists on the order.

      • The order contains a completed fulfillment. The seller needs to perform a refund in Square Point of Sale if necessary after the order is COMPLETED.

      Note that order.state cannot be set to CANCELED if the order contains a completed fulfillment. The seller needs to perform a refund in Square Point of Sale if necessary after the order is COMPLETED.

  • A fulfillment fails to complete:

    • Specify a reason why the fulfillment failed in the FulfillmentDeliveryDetails.notes field.

    • Set fulfillment.state to FAILED.

    • Set order.state to COMPLETED.

      Note that order.state cannot be set to CANCELED if the order contains a completed fulfillment. The seller needs to perform a refund in Square Point of Sale if necessary after the order is COMPLETED.

You cannot delete a fulfillment from an order. You can only cancel a fulfillment using the UpdateOrder endpoint as shown:

In the request, you provide the Order object with the following information in the request body:

  • The version of the order.

  • The fulfillments array identifying the specific fulfillment. You provide the fulfillment UID being updated and specify the value of the state field as CANCELED.

If you need more assistance, contact Developer Support or ask for help in the Developer Forums.