> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ordergroove.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ordergroove.com/_mcp/server.

# Subscription Creation via Purchase POST

When any user completes checkout, Ordergroove needs to be notified about this event. You will send a secure HTTP POST that provides Ordergroove with the necessary information to create one or more subscriptions on our servers. Ordergroove expects a purchase POST regardless of whether or not the customer is checking out with a subscription item. If there is a subscription item, Ordergroove will create a new subscription and allow the customer to begin managing it. If there is no subscription item, Ordergroove will log the OG cart session as a non-subscription checkout and clear the cart session.

#### Required for All Checkouts

Ordergroove requires that every checkout from your store results in a purchase POST, whether or not it contains a subscription. Critical analytics data for subscription conversion and program efficacy depend on this data to provide a complete picture of your subscription program's performance. Please test and confirm that all checkouts are sending purchase POSTs to Ordergroove.

***

## Request Structure

**Destination**

* Staging: `https://staging.sc.ordergroove.com/subscription/create`
* Production: `https://sc.ordergroove.com/subscription/create`

**API Keys**

* Staging: `https://rc3.stg.ordergroove.com/keys/`

* Production: `https://rc3.ordergroove.com/keys/`

* All fields in the request are required for Ordergroove's subscription creation validation unless noted as optional.

* If you choose not to send `cc_exp_date` and `cc_type` (which are optional), you will not be able to use Ordergroove's credit card expiring soon email notifications.

* Any requests made to the Ordergroove servers from your application should be accompanied with a 5-second timeout. In the event that Ordergroove is unavailable, your application should be able to continue to run seamlessly.

* Each string in the body of the POST must be URL encoded. Do **not** URL encode the entire POST, and do **not** URL encode the authorization headers.

```text title="Header Format"
x-api-key:<REPLACE_ME_WITH_API_KEY>
```

```text title="Example Header"
x-api-key:5DVCQ2fCQkCkpP1AYyWAdB2G9QjgRVJ428UcHksCuD55owwBiaqLQWctzGAQssfpsp42w7VYFaXrhY5TtxCUQu2
```

```text title="Request Body"
create_request={
  "merchant_id": "<MERCHANT_PUBLIC_ID>",
  "og_cart_tracking": false,
  "merchant_order_id": "abc123",
  "user": {
    "user_id": "<MERCHANT_USER_ID>",
    "first_name": "Nicholas",
    "last_name": "Bundy",
    "email": "nicholas.bundy@ordergroove.com",
    "phone_number": "555-555-5555",
    "shipping_address": {
      "first_name": "Nicholas",
      "last_name": "Bundy",
      "company_name": "Ordergroove", // Optional
      "address": "75 Broad Street",
      "address2": "23rd Floor", // Optional
      "city": "New York",
      "state_province_code": "NY",
      "zip_postal_code": "10004",
      "phone": "555-555-5555",
      "fax": "", // Optional
      "country_code": "US" // Must be two characters maximum
    },
    "billing_address": { // Optional - OG can store billing address fields if needed
      "first_name": "Nicholas",
      "last_name": "Bundy",
      "company_name": "Ordergroove", // Optional
      "address": "75 Broad Street",
      "address2": "23rd Floor", // Optional
      "city": "New York",
      "state_province_code": "NY",
      "zip_postal_code": "10004",
      "phone": "555-555-5555",
      "fax": "", // Optional
      "country_code": "US" // Must be two characters maximum
    }
  },
  "payment": { // cc_exp_date and cc_type are optional
    "token_id": "7654321",
    "cc_exp_date": "<AES_ENCRYPTED_CC_EXP_DATE>", // Format: MM/YYYY e.g. 01/2019 | AES encrypted, then URL encoded | Use 12/2099 for PayPal
    "cc_type": "1" // 1 = Visa, 2 = MasterCard, 3 = American Express, 4 = Discover
  },
  "products": [
    {
      "product": "123456789",
      "sku": "123456789",
      "subscription_info": {
        "quantity": 2,
        "tracking_override": {
          "offer": "903ecf3e5efc12e49d61bc764e106cf6",
          "every": 4,
          "every_period": 2
        }
      },
      "purchase_info": {
        "quantity": "2",
        "price": "2.00", // price per unit
        "discounted_price": "1.90", // price per unit after discount
        "total": "3.80" // discounted_price * quantity
      }
    }
  ]
}
```

#### Building the Products Array

If you are using Ordergroove's JavaScript-injected offers, you can call `OG.getOptins()` which will return everything you need to place within the `products` array. If you are hosting your own enrollment experience, you will need to construct the `products` array as shown in the example above.

***

## Additional Purchase POST Objects

**`subscription_info`**

* `first_order_place_date` — Defines when the first recurring order will be placed for this subscription.
* `extra_data` — Any information you want stored at the subscription level and passed back at the time of order placement.
* `components` — Sets components within a legacy bundle subscription.
* `multi_item_bundle_components` — Creates a new bundle subscription. Multiple bundle items will be linked to this subscription. The subscription product should be a bundle `product_type` while the products in the array should be standard products.
* `subscription_type` — If set to `prepaid`, creates a prepaid subscription. Also requires `prepaid_orders_per_billing` to define how many orders were paid for:

```json
"products": {
  "subscription_info": {
    "subscription_type": "prepaid",
    "prepaid_orders_per_billing": 1,
    "renewal_behavior": "autorenew",
    "price": "12",
    "quantity": 1
  },
  "product": "123",
  "sku": "123"
}
```

**`tracking_override`**

* `product` — Allows you to define a different product for the subscription to be created against (use case: buy X, subscribe to Y).

**Example**

This example highlights all of the additional objects above and where they live within the `products` array:

```json
[
  {
    "product": "10365",
    "subscription_info": {
      "components": [
        "B987654",
        "B987654",
        "C000000",
        "C000000"
      ],
      "first_order_place_date": "2022-05-01",
      "extra_data": {
        "pet_name": "Rover",
        "breed": "Great Pyranese"
      }
    },
    "multi_item_bundle_components": [
      {
        "product": "41049345949751",
        "quantity": 2
      },
      {
        "product": "40969287073847",
        "quantity": 2
      },
      {
        "product": "40967805337655",
        "quantity": 2
      }
    ],
    "tracking_override": {
      "every": 2,
      "every_period": 3,
      "offer": "cfec81b6be4b11ebb3580ef6d8743325",
      "product": "10000"
    }
  }
]
```

#### Additional Information

See the [Purchase POST API Endpoint](/reference) for more information about request body parameters.

***

## Purchase POST Responses

If a successful connection is made, the request will always result in a secure HTTP response with code `200`, `201`, or `206` and a JSON payload.

**Success — Request Received**

```json
{"result": "Subscription request received", "subs_req_id": "59f215d4b3ade33e68c8ae9b"}
```

**Error Responses**

Given the amount of data provided and the order in which the payload is validated and created, there will be instances where a `207`, `400`, `401`, or `409` status is returned. In these cases, the customer, shipping, and payment Ordergroove IDs will be provided as they were created, even if there was an issue with some or all products in the request.

* `207` — Request contained multiple subscriptions and some were successfully created while others were not.
* `400` — Invalid request. No subscriptions were created. Provides details about what was missing or invalid.
* `401`/`403` — Authentication failed.
* `409` — Conflict: a request with the given `merchant_order_id` was already received and processed.

If there are errors, they will appear in the `errors` object of the response. Some examples:

```json
{"error": "Invalid Merchant MERCHANT_PUBLIC_ID"}
{"error": "Merchant ID must be a string"}
{"error_message": "Merchant order id cannot be null"}
{"error_message": "Missing payment data to create record"}
{"error_message": "The credit card encryption is not valid"}
{"error_message": "Expiration date is not valid, received: "}
{"error_message": "Paymetric tokenization error"}
```

**Error Logging and Retry Logic**

It is recommended that you set up email notifications for `400`, `401`, `403`, and `409` error responses. If an issue can be identified and corrected within 24 hours, the POST should be resent to Ordergroove. If multiple POSTs are returning the same response, it likely points to a larger integration issue that should be investigated. Any retries of `409` responses will need the `merchant_order_id` field modified.

For `500`-level errors, re-send the POST up to 3 times within the next 10 minutes. If there is still no successful connection, retry again after 24 hours. After 24 hours, no further retries should be attempted as the contents of the customer's cart are no longer reliable.