# Complete checkout

URL: https://docs.sparklayer.io/ignite/api/complete-checkout
Operation: `POST /v1/{siteEnv}/{siteId}/checkout/complete` (operationId `completeOrder`)
OpenAPI spec: https://docs.sparklayer.io/openapi/ignite.yaml

This endpoint is called at the final step once the customer attempts to complete the order. If the payment type is `upfrontPayment` the customer should be directed to the checkout flow to complete payment. Alternatively, an order can be created there and then for other systems to manage payments.

At this point, either redirect the user to a URL to complete the transaction or return a ID of the order being created on the platform.

`POST /v1/{siteEnv}/{siteId}/checkout/complete`

> This is an Ignite endpoint: your integration service implements it and SparkLayer calls it.

### Request SparkLayer sends

```http
POST /v1/live/bobs-store/checkout/complete HTTP/1.1
Host: ignite.example.com
Content-Type: application/json

{
  "cart_id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
  "customer": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "external_id": "CUS1234",
    "accounting_id": "<accounting_id>",
    "default_billing_address_id": "<default_billing_address_id>",
    "default_shipping_address_id": "<default_shipping_address_id>",
    "temporary_external_address_ids": [
      "<temporary_external_address_ids>"
    ],
    "payment_on_account": {
      "credit_limit": 0,
      "balance": 0,
      "currency_code": "<currency_code>",
      "net_terms": "7_days"
    }
  },
  "currency_code": "gbp",
  "billing_address": {
    "title": "Mr",
    "first_name": "Bob",
    "last_name": "Jones",
    "company": "Tom Jones Climbing Ltd",
    "address_line1": "Example Industrial Estate",
    "address_line2": "North Country",
    "city": "Cityland",
    "region_name": "California",
    "region_code": "CA",
    "postal_code": "12345",
    "country_code": "US",
    "phone": "+44 (0) 123456789",
    "is_default_shipping": true,
    "is_default_billing": true,
    "is_temporary": true
  },
  "shipping_address": {
    "title": "Mr",
    "first_name": "Bob",
    "last_name": "Jones",
    "company": "Tom Jones Climbing Ltd",
    "address_line1": "Example Industrial Estate",
    "address_line2": "North Country",
    "city": "Cityland",
    "region_name": "California",
    "region_code": "CA",
    "postal_code": "12345",
    "country_code": "US",
    "phone": "+44 (0) 123456789",
    "is_default_shipping": true,
    "is_default_billing": true,
    "is_temporary": true
  },
  "shipping_line": {
    "type": "platform",
    "id": "<id>",
    "name": "<name>",
    "price": 4.8,
    "tax_rate": 0.2
  },
  "internal_shipping_methods": [
    {
      "title": "<title>",
      "price_v2": {
        "tax_rate": 0,
        "net": 0,
        "gross": 0,
        "currency_code": "<currency_code>"
      },
      "handle": "<handle>",
      "cost_type": "<cost_type>",
      "cost_language_string": "<cost_language_string>"
    }
  ],
  "shop": {
    "base_currency_code": "gbp"
  },
  "line_items": [
    {
      "type": "product",
      "spark_item_key": "00a0c91e6bf600a0c91e6bf",
      "spark_variant_id": "8ac52999-d163-4d68-ae30-a5f0c089ed79",
      "sku": "EXAMPLE-SKU",
      "product_variant_external_id": "PROD123456",
      "product_external_id": "PROD1234",
      "quantity": 10,
      "unit_price": 4.8,
      "custom_attributes": [
        {
          "key": "<key>",
          "value": "<value>"
        }
      ],
      "options": [
        {
          "group": "<group>",
          "value": "<value>"
        }
      ]
    }
  ],
  "ignite_state": {},
  "ignite_checkout_context": {
    "channel_id": 12345
  },
  "shipping_method_source": "sparklayer",
  "payment_type": "upfrontPayment",
  "sales_agent": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "accounting_id": "<accounting_id>"
  },
  "company_user": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "external_id": "CUS1234",
    "accounting_id": "<accounting_id>"
  },
  "additional_info": "<additional_info>",
  "po_number": "PO-001",
  "shipping_requested_date": "2020-01-01T00:00:00+02:00",
  "custom_fields": {},
  "discount_data": {
    "sub_total_pre_discount": {
      "net": 0
    },
    "sub_total_discount": {
      "net": 0
    },
    "shipping_pre_discount": {
      "net": 0
    },
    "shipping_discount": {
      "net": 0
    },
    "line_item_discounts": [
      {
        "pre_discount": {
          "net": 0
        },
        "discount": {
          "net": 0
        },
        "sku": "<sku>",
        "item_key": "<item_key>"
      }
    ],
    "discount_slugs": [
      "<discount_slugs>"
    ]
  },
  "discount_coupon_codes": [
    "<discount_coupon_codes>"
  ]
}
```

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `siteEnv` | string | Yes | The SparkLayer environment the request is for, such as `live`. Store it, with the site ID, when SparkLayer connects your platform. Example: `live` |
| `siteId` | string | Yes | The SparkLayer site ID the request is for, such as `bobs-store`. Store it, with the environment, when SparkLayer connects your platform. Length: min 1. Example: `bobs-store` |

### Request body (`application/json`) (required)

Checkout.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `cart_id` | string (uuid) | | SparkLayer Cart ID |
| `customer` | object | | |
| `customer.id` | string | Yes | SparkLayer ID of Customer |
| `customer.email` | string (email) | Yes | |
| `customer.external_id` | string | Yes | eCommerce platform ID of Customer |
| `customer.accounting_id` | string \| null | | |
| `customer.default_billing_address_id` | string \| null | | eCommerce platform ID of default billing address |
| `customer.default_shipping_address_id` | string \| null | | eCommerce platform ID of default shipping address |
| `customer.temporary_external_address_ids` | string[] | | List of temporary (drop shipping) address IDs associated with the customer to be deleted once the order has been completed. Should be the external (platform) address ID |
| `customer.payment_on_account` | object \| null | | |
| `customer.payment_on_account.credit_limit` | number (float) \| null | | Max 999999999.999. |
| `customer.payment_on_account.balance` | number (float) \| null | | Max 999999999.999. |
| `customer.payment_on_account.currency_code` | string \| null | | If set allows overriding the currency for the customer, otherwise the base currency of the store is to be used. Pattern: `^[A-Za-z]{3}$`. |
| `customer.payment_on_account.net_terms` | "7_days" \| "15_days" \| "30_days" \| "45_days" \| "60_days" \| "90_days" \| null | | |
| `currency_code` | string | | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code. Length: min 3, max 3. |
| `billing_address` | object | | |
| `billing_address.title` | string \| null | | Length: max 30. |
| `billing_address.first_name` | string \| null | | Length: max 50. |
| `billing_address.last_name` | string \| null | | Length: max 50. |
| `billing_address.company` | string \| null | | Length: max 128. |
| `billing_address.address_line1` | string | | Length: max 255. |
| `billing_address.address_line2` | string \| null | | Length: max 255. |
| `billing_address.city` | string | | Length: max 128. |
| `billing_address.region_name` | string \| null | | Length: max 128. |
| `billing_address.region_code` | string \| null | | Length: max 10. |
| `billing_address.postal_code` | string \| null | | Length: max 20. |
| `billing_address.country_code` | string | | Two letter country code as defined by ISO 3166-2. Length: max 2. |
| `billing_address.phone` | string | | Length: max 20. |
| `billing_address.is_default_shipping` | boolean | | |
| `billing_address.is_default_billing` | boolean | | |
| `billing_address.is_temporary` | boolean | | Whether the address is temporary for the duration of a cart. This value is only relevant to platforms that create the order address automatically on order creation (or conversion from draft to normal order as in the case of our Shopify integration). In such cases we will want the integration to ensure this address does not get created in SparkLayer when the platform notifes the integration of a new customer address. |
| `shipping_address` | object | | |
| `shipping_address.title` | string \| null | | Length: max 30. |
| `shipping_address.first_name` | string \| null | | Length: max 50. |
| `shipping_address.last_name` | string \| null | | Length: max 50. |
| `shipping_address.company` | string \| null | | Length: max 128. |
| `shipping_address.address_line1` | string | | Length: max 255. |
| `shipping_address.address_line2` | string \| null | | Length: max 255. |
| `shipping_address.city` | string | | Length: max 128. |
| `shipping_address.region_name` | string \| null | | Length: max 128. |
| `shipping_address.region_code` | string \| null | | Length: max 10. |
| `shipping_address.postal_code` | string \| null | | Length: max 20. |
| `shipping_address.country_code` | string | | Two letter country code as defined by ISO 3166-2. Length: max 2. |
| `shipping_address.phone` | string | | Length: max 20. |
| `shipping_address.is_default_shipping` | boolean | | |
| `shipping_address.is_default_billing` | boolean | | |
| `shipping_address.is_temporary` | boolean | | Whether the address is temporary for the duration of a cart. This value is only relevant to platforms that create the order address automatically on order creation (or conversion from draft to normal order as in the case of our Shopify integration). In such cases we will want the integration to ensure this address does not get created in SparkLayer when the platform notifes the integration of a new customer address. |
| `shipping_line` | ShippingLine \| ShippingLinePlatformIdOnly \| null | | If using platform shipping, on the first load of the final checkout screen, this will be `null`, after it will be an ID from a method from the response of `available_shipping_methods` If using SparkLayer shipping, this can be `null` if none found or will be the method. |
| `internal_shipping_methods` | object[] \| null | | **Deprecated.** List of available SparkLayer shipping methods for the given checkout, if not using spark shipping this will be empty. |
| `internal_shipping_methods[].title` | string | | |
| `internal_shipping_methods[].price_v2` | object | | |
| `internal_shipping_methods[].price_v2.tax_rate` | number | | |
| `internal_shipping_methods[].price_v2.net` | number | | |
| `internal_shipping_methods[].price_v2.gross` | number | | |
| `internal_shipping_methods[].price_v2.currency_code` | string | | |
| `internal_shipping_methods[].handle` | string | | |
| `internal_shipping_methods[].cost_type` | string | | |
| `internal_shipping_methods[].cost_language_string` | string \| null | | |
| `shop` | object | | |
| `shop.base_currency_code` | string | | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code. Length: min 3, max 3. |
| `line_items` | (LineItemProduct \| LineItemCustom)[] | | |
| `line_items[].type` | "product" | | |
| `line_items[].spark_item_key` | string | | Length: max 32. |
| `line_items[].spark_variant_id` | string | | Length: max 36. |
| `line_items[].sku` | string | | |
| `line_items[].product_variant_external_id` | string | | eCommerce platform ID of Product Variant |
| `line_items[].product_external_id` | string | | eCommerce platform ID of Product |
| `line_items[].quantity` | integer | | |
| `line_items[].unit_price` | number | | Net price of a unit |
| `line_items[].custom_attributes` | object[] | | Custom attributes allow arbitrary data to be attached to a line item |
| `line_items[].custom_attributes[].key` | string | | |
| `line_items[].custom_attributes[].value` | string | | |
| `line_items[].options` | object[] \| null | | |
| `line_items[].options[].group` | string | | |
| `line_items[].options[].value` | string | | |
| `line_items[].name` | string | | Length: max 128. |
| `ignite_state` | object | | Context which was set by a previous response from /checkout/calculate |
| `ignite_checkout_context` | object \| null | | Extra context provided by the checkout frontend. This allows passing arbitrary platform-specific data that might be needed by the platform's checkout process. For example, for BigCommerce, this could be used to pass a `channel_id` from the store theme to the ignite integration in order to support multi-channel stores. |
| `shipping_method_source` | "sparklayer" \| "platform" | | Specifies the store's configured source for retrieving shipping methods during checkout. When `sparklayer`, a `null` `shipping_line` means the cart has no shipping charge, and no platform rate is fetched or applied. Absent is treated as `platform`. |
| `payment_type` | "upfrontPayment" \| "paymentOnAccount" \| "paymentByInvoice" \| "quote" | | |
| `sales_agent` | object \| null | | |
| `sales_agent.id` | string | Yes | SparkLayer ID of Sales Agent |
| `sales_agent.email` | string (email) | Yes | |
| `sales_agent.accounting_id` | string \| null | | |
| `company_user` | object \| null | | |
| `company_user.id` | string | Yes | SparkLayer ID of Customer |
| `company_user.email` | string (email) | Yes | |
| `company_user.external_id` | string | Yes | eCommerce platform ID of Customer |
| `company_user.accounting_id` | string \| null | | |
| `additional_info` | string \| null | | An optional note to be added to the order. |
| `po_number` | string \| null | | PO number for the purchase |
| `shipping_requested_date` | string (date-time) \| null | | The date requested for the delivery to arrive |
| `custom_fields` | object \| null | | Custom fields to be added to the order. These are customer defined and dynamic. |
| `discount_data` | object \| null | | |
| `discount_data.sub_total_pre_discount` | object | Yes | |
| `discount_data.sub_total_pre_discount.net` | number (float) | Yes | |
| `discount_data.sub_total_discount` | object | Yes | |
| `discount_data.sub_total_discount.net` | number (float) | Yes | |
| `discount_data.shipping_pre_discount` | object | | |
| `discount_data.shipping_pre_discount.net` | number (float) | Yes | |
| `discount_data.shipping_discount` | object | | |
| `discount_data.shipping_discount.net` | number (float) | Yes | |
| `discount_data.line_item_discounts` | object[] | Yes | |
| `discount_data.line_item_discounts[].pre_discount` | object | Yes | |
| `discount_data.line_item_discounts[].pre_discount.net` | number (float) | Yes | |
| `discount_data.line_item_discounts[].discount` | object | Yes | |
| `discount_data.line_item_discounts[].discount.net` | number (float) | Yes | |
| `discount_data.line_item_discounts[].sku` | string | Yes | |
| `discount_data.line_item_discounts[].item_key` | string | Yes | |
| `discount_data.discount_slugs` | string[] | Yes | |
| `discount_coupon_codes` | string[] \| null | | A list of all the coupon codes applied to the order |

```json
{
  "cart_id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
  "customer": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "external_id": "CUS1234",
    "accounting_id": "<accounting_id>",
    "default_billing_address_id": "<default_billing_address_id>",
    "default_shipping_address_id": "<default_shipping_address_id>",
    "temporary_external_address_ids": [
      "<temporary_external_address_ids>"
    ],
    "payment_on_account": {
      "credit_limit": 0,
      "balance": 0,
      "currency_code": "<currency_code>",
      "net_terms": "7_days"
    }
  },
  "currency_code": "gbp",
  "billing_address": {
    "title": "Mr",
    "first_name": "Bob",
    "last_name": "Jones",
    "company": "Tom Jones Climbing Ltd",
    "address_line1": "Example Industrial Estate",
    "address_line2": "North Country",
    "city": "Cityland",
    "region_name": "California",
    "region_code": "CA",
    "postal_code": "12345",
    "country_code": "US",
    "phone": "+44 (0) 123456789",
    "is_default_shipping": true,
    "is_default_billing": true,
    "is_temporary": true
  },
  "shipping_address": {
    "title": "Mr",
    "first_name": "Bob",
    "last_name": "Jones",
    "company": "Tom Jones Climbing Ltd",
    "address_line1": "Example Industrial Estate",
    "address_line2": "North Country",
    "city": "Cityland",
    "region_name": "California",
    "region_code": "CA",
    "postal_code": "12345",
    "country_code": "US",
    "phone": "+44 (0) 123456789",
    "is_default_shipping": true,
    "is_default_billing": true,
    "is_temporary": true
  },
  "shipping_line": {
    "type": "platform",
    "id": "<id>",
    "name": "<name>",
    "price": 4.8,
    "tax_rate": 0.2
  },
  "internal_shipping_methods": [
    {
      "title": "<title>",
      "price_v2": {
        "tax_rate": 0,
        "net": 0,
        "gross": 0,
        "currency_code": "<currency_code>"
      },
      "handle": "<handle>",
      "cost_type": "<cost_type>",
      "cost_language_string": "<cost_language_string>"
    }
  ],
  "shop": {
    "base_currency_code": "gbp"
  },
  "line_items": [
    {
      "type": "product",
      "spark_item_key": "00a0c91e6bf600a0c91e6bf",
      "spark_variant_id": "8ac52999-d163-4d68-ae30-a5f0c089ed79",
      "sku": "EXAMPLE-SKU",
      "product_variant_external_id": "PROD123456",
      "product_external_id": "PROD1234",
      "quantity": 10,
      "unit_price": 4.8,
      "custom_attributes": [
        {
          "key": "<key>",
          "value": "<value>"
        }
      ],
      "options": [
        {
          "group": "<group>",
          "value": "<value>"
        }
      ]
    }
  ],
  "ignite_state": {},
  "ignite_checkout_context": {
    "channel_id": 12345
  },
  "shipping_method_source": "sparklayer",
  "payment_type": "upfrontPayment",
  "sales_agent": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "accounting_id": "<accounting_id>"
  },
  "company_user": {
    "id": "cu_1",
    "email": "buyer@example.com",
    "external_id": "CUS1234",
    "accounting_id": "<accounting_id>"
  },
  "additional_info": "<additional_info>",
  "po_number": "PO-001",
  "shipping_requested_date": "2020-01-01T00:00:00+02:00",
  "custom_fields": {},
  "discount_data": {
    "sub_total_pre_discount": {
      "net": 0
    },
    "sub_total_discount": {
      "net": 0
    },
    "shipping_pre_discount": {
      "net": 0
    },
    "shipping_discount": {
      "net": 0
    },
    "line_item_discounts": [
      {
        "pre_discount": {
          "net": 0
        },
        "discount": {
          "net": 0
        },
        "sku": "<sku>",
        "item_key": "<item_key>"
      }
    ],
    "discount_slugs": [
      "<discount_slugs>"
    ]
  },
  "discount_coupon_codes": [
    "<discount_coupon_codes>"
  ]
}
```

### Responses your service returns

#### 201: Checkout complete success

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `line_items` | object[] | | |
| `line_items[].spark_item_key` | string | Yes | |
| `line_items[].tax_lines` | object[] | Yes | |
| `line_items[].tax_lines[].rate` | number | | Tax rate |
| `line_items[].tax_lines[].price` | number | | Tax amount |
| `platform_shipping_line` | object | | The shipping line applied to the order in the eCommerce platform. Determines price and tax amounts for SparkLayer. |
| `platform_shipping_line.type` | "platform" \| "sparklayer" | | |
| `platform_shipping_line.id` | string | | |
| `platform_shipping_line.name` | string | | |
| `platform_shipping_line.price` | number | | Net of tax |
| `platform_shipping_line.tax_rate` | number | | |

```json
{
  "line_items": [
    {
      "spark_item_key": "<spark_item_key>",
      "tax_lines": [
        {
          "rate": 0.2,
          "price": 1
        }
      ]
    }
  ],
  "platform_shipping_line": {
    "type": "platform",
    "id": "<id>",
    "name": "<name>",
    "price": 4.8,
    "tax_rate": 0.2
  },
  "checkout_url": "https://checkout-bobs-store.com/checkout/1234/payment"
}
```

#### 401: Auth Failure

#### 500: System Exception
