Update Subscription Plan
curl --request POST \
--url https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"new_price_id": "<string>",
"proration_behavior": "create_prorations"
}
'import requests
url = "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription"
payload = {
"new_price_id": "<string>",
"proration_behavior": "create_prorations"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({new_price_id: '<string>', proration_behavior: 'create_prorations'})
};
fetch('https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'new_price_id' => '<string>',
'proration_behavior' => 'create_prorations'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription"
payload := strings.NewReader("{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}"
response = http.request(request)
puts response.read_body{
"subscription_id": "<string>",
"status": "<string>",
"price_id": "<string>",
"message": "<string>"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Stripe Subscriptions
Update Subscription Plan
Change the user’s subscription to a different plan (upgrade or downgrade)
POST
/
api
/
v1
/
payments
/
stripe
/
update-subscription
Update Subscription Plan
curl --request POST \
--url https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"new_price_id": "<string>",
"proration_behavior": "create_prorations"
}
'import requests
url = "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription"
payload = {
"new_price_id": "<string>",
"proration_behavior": "create_prorations"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({new_price_id: '<string>', proration_behavior: 'create_prorations'})
};
fetch('https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'new_price_id' => '<string>',
'proration_behavior' => 'create_prorations'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription"
payload := strings.NewReader("{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"new_price_id\": \"<string>\",\n \"proration_behavior\": \"create_prorations\"\n}"
response = http.request(request)
puts response.read_body{
"subscription_id": "<string>",
"status": "<string>",
"price_id": "<string>",
"message": "<string>"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Change the authenticated user’s subscription to a different plan. Proration is applied by default, adjusting the billing amount based on time remaining in the current period.
Authentication
This endpoint requires end user authentication via HTTP Bearer Token with project scope.
Query Parameters
boolean
default:"true"
Use test mode credentials. Set to
false for production.Request Body
string
required
Stripe Price ID for the new plan (e.g.,
price_1ABC123def456)string
default:"create_prorations"
How to handle proration:
create_prorations- Apply credit/charge for prorated amountnone- No proration; new price applies next billing cyclealways_invoice- Invoice immediately for prorated amount
Response
string
Stripe subscription ID
string
Subscription status after update
string
New active Price ID
string
Human-readable confirmation message
Example Request
curl -X POST "https://api.devkit4ai.com/api/v1/payments/stripe/update-subscription?test_mode=true" \
-H "Authorization: Bearer {end_user_jwt}" \
-H "Content-Type: application/json" \
-d '{
"new_price_id": "price_1XYZ789abc123",
"proration_behavior": "create_prorations"
}'
Example Response
{
"subscription_id": "sub_1ABC123def456",
"status": "active",
"price_id": "price_1XYZ789abc123",
"message": "Subscription updated to new plan successfully."
}
Proration Behaviors
Proration Examples
| Scenario | Current | New | Proration |
|---|---|---|---|
| Upgrade | $10/mo | $20/mo | Charge difference prorated |
| Downgrade | $20/mo | $10/mo | Credit applied to next invoice |
| Same price | $10/mo | $10/mo | No change in billing |
Integration Example
// Plan upgrade/downgrade component
function ChangePlanModal({ currentPriceId, plans }) {
const [selectedPlan, setSelectedPlan] = useState(currentPriceId);
const [loading, setLoading] = useState(false);
const handleChangePlan = async () => {
if (selectedPlan === currentPriceId) return;
setLoading(true);
try {
const response = await fetch('/api/update-subscription', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
new_price_id: selectedPlan,
proration_behavior: 'create_prorations'
})
});
const result = await response.json();
showToast(result.message);
closeModal();
refreshSubscriptionStatus();
} catch (error) {
showError('Failed to update plan');
} finally {
setLoading(false);
}
};
return (
<div>
<h2>Change Your Plan</h2>
{plans.map(plan => (
<PlanCard
key={plan.price_id}
plan={plan}
selected={selectedPlan === plan.price_id}
current={currentPriceId === plan.price_id}
onSelect={() => setSelectedPlan(plan.price_id)}
/>
))}
<button onClick={handleChangePlan} disabled={loading}>
{loading ? 'Updating...' : 'Confirm Change'}
</button>
</div>
);
}
Upgrade vs Downgrade UX
UX Best Practice: Show users what they’ll pay or save before confirming the change. Use Stripe’s preview invoice API to calculate exact amounts.
Error Responses
| Status | Description |
|---|---|
400 | Invalid price ID or incompatible plan |
401 | Unauthorized - Invalid or missing authentication |
404 | No active subscription to update |
404 | Project not found or Stripe not configured |
422 | Validation error - Invalid parameters |
Related Pages
Get My Subscription
Check current subscription
Create Checkout
Start new subscription
Cancel Subscription
End subscription
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
Use test mode
Body
application/json

