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

# Upgrade Subscription To Prepaid

PATCH https://restapi.ordergroove.com/subscriptions/{subscription_id}/upgrade_to_prepaid/
Content-Type: application/json

Upgrades a pay-as-you-go subscription to a prepaid subscription.

Returns `400`, with the reason in `detail`, when the merchant doesn't have prepaid subscriptions enabled, the subscription is already prepaid or isn't `live`, `orders_per_billing` is missing or less than `2`, or the subscription's product isn't prepaid-eligible (in the `prepaid` eligibility product group).

The upgraded subscription starts with `prepaid_orders_remaining` at `0`, so its next order is a renewal. That order is repriced right away to `orders_per_billing` times the unit price, and the customer pays for the full prepaid cycle when it's placed. Because the customer never receives an order they haven't paid for, the upgrade can be offered directly in the Subscription Manager. If `renewal_behavior` is omitted, the merchant's default renewal behavior applies, or `autorenew` if none is set.

Reference: https://developer.ordergroove.com/reference/rest-rpc-api/subscriptions/upgrade-to-prepaid-subscription

## Authentication

- `x-api-key` header (required) — Application API Scope — server-to-server, sent in the `x-api-key` header. See [Authentication](/api-reference/authentication).
- `authorization` header (required) — Storefront API Scope — client-side, scoped to one customer, sent as a signature in the `authorization` header. See [Authentication](/api-reference/authentication).

## Request

### Path parameters

- `subscription_id` (string, required) — Unique subscription ID

### Body (application/json)

This endpoint expects an object.

- `orders_per_billing` (integer, required) — Number of orders per prepaid billing cycle. Must be at least `2`.
- `renewal_behavior` (enum, optional, default: autorenew)
  - Allowed values: `autorenew`, `cancel`, `downgrade`
- `offer` (string, optional) — Public ID of the offer to associate the subscription with after the upgrade, or `live` for the merchant's currently live offer. When omitted, the subscription keeps its current offer.

## Response

### 200

200

- `customer` (string, optional)
- `merchant` (string, optional)
- `product` (string, optional)
- `payment` (string, optional)
- `shipping_address` (string, optional)
- `offer` (string, optional)
- `subscription_type` (string, optional)
- `raw_subscription_type` (string, optional)
- `components` (list of SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaComponentsItems, optional)
- `extra_data` (SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaExtraData, optional)
- `public_id` (string, optional)
- `quantity` (integer, optional, default: 0)
- `price` (string, optional, nullable)
- `frequency_days` (integer, optional, default: 0)
- `reminder_days` (integer, optional, default: 0)
- `every` (integer, optional, default: 0)
- `every_period` (integer, optional, default: 0)
- `start_date` (string, optional)
- `cancelled` (string, optional, nullable)
- `cancel_reason` (string, optional, nullable)
- `iteration` (any, optional)
- `sequence` (any, optional)
- `session_id` (string, optional)
- `merchant_order_id` (string, optional)
- `created` (string, optional)
- `updated` (string, optional)
- `live` (boolean, optional, default: true)
- `external_id` (string, optional)
- `product_attribute` (any, optional)
- `cancel_reason_code` (integer, optional, nullable)
- `customer_rep` (integer, optional, nullable)
- `club` (any, optional)
- `queued_actions` (list of SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaQueuedActionsItems, optional)
- `prepaid_subscription_context` (SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaPrepaidSubscriptionContext, optional)

## Errors

### 400 Bad Request Error

400

## Types

### SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaComponentsItems

### SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaExtraData

- `shopify_contract_id` (string, optional)

### SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaQueuedActionsItems

### SubscriptionsSubscriptionIdUpgradeToPrepaidPatchResponsesContentApplicationJsonSchemaPrepaidSubscriptionContext

- `prepaid_orders_remaining` (integer, optional, default: 0)
- `prepaid_orders_per_billing` (integer, optional, default: 0)
- `renewal_behavior` (string, optional)

## Examples

**Request**

```json
{
  "orders_per_billing": 1
}
```

**Response**

```json
{
  "customer": "00026001",
  "merchant": "ac4f7938383a11e89ecbbc764e1107f2",
  "product": "0070000693",
  "payment": "070001bc02fd11e99542bc764e1043b0",
  "shipping_address": "66c25cd0564011e9abc5bc764e107990",
  "offer": "a748aa648ac811e8af3bbc764e106cf4",
  "subscription_type": "replenishment",
  "raw_subscription_type": "replenishment",
  "components": [],
  "extra_data": {
    "shopify_contract_id": "gid://shopify/SubscriptionContract/2287823"
  },
  "public_id": "607daa2accc811e88516bc764e106cf4",
  "quantity": 1,
  "price": null,
  "frequency_days": 30,
  "reminder_days": 4,
  "every": 1,
  "every_period": 3,
  "start_date": "2023-05-30",
  "cancelled": null,
  "cancel_reason": null,
  "session_id": "ac4f7938383a11e89ecbbc764e1107f2.896371.1539022086",
  "merchant_order_id": "#1144",
  "created": "2023-05-30 13:20:41",
  "updated": "2023-10-03 10:22:11",
  "live": true,
  "external_id": "2287823",
  "cancel_reason_code": null,
  "customer_rep": null,
  "queued_actions": [],
  "prepaid_subscription_context": {
    "prepaid_orders_remaining": 4,
    "prepaid_orders_per_billing": 6,
    "renewal_behavior": "autorenew"
  }
}
```

**SDK Code**

```python Result
import requests

url = "https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/"

payload = { "orders_per_billing": 1 }
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())
```

```javascript Result
const url = 'https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/';
const options = {
  method: 'PATCH',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"orders_per_billing":1}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Result
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/"

	payload := strings.NewReader("{\n  \"orders_per_billing\": 1\n}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Result
require 'uri'
require 'net/http'

url = URI("https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"orders_per_billing\": 1\n}"

response = http.request(request)
puts response.read_body
```

```java Result
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.patch("https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"orders_per_billing\": 1\n}")
  .asString();
```

```php Result
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/', [
  'body' => '{
  "orders_per_billing": 1
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp Result
using RestSharp;

var client = new RestClient("https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/");
var request = new RestRequest(Method.PATCH);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"orders_per_billing\": 1\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Result
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["orders_per_billing": 1] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://restapi.ordergroove.com/subscriptions/subscription_id/upgrade_to_prepaid/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```