Update plan (Usage-Based only)
Overview
Update an existing partner-managed usage-based plan. Features are fully replaced each call (old PlanFeature rows deleted and re-inserted). Review sites are synced in place: surviving rows keep their ids/timestamps, and only sites removed from the payload are deleted.
Prerequisites
- A bearer token. Callable with Partner tokens.
- The
planIdof the record you are targeting.
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
POST /api/v1/partner/plans/{planId}/update
Authentication
-
Requires a bearer token in the
Authorization: Bearer <bearer-token>header. -
Who can call it: Partner tokens.
-
Usage-based only. Sits in the authenticated group, with no extra route-level guard.
-
updatePartnerPlanresolves the partner viagetAuthPartner(403 if none). -
403 unless
billing_model === 'usage-based'. -
404 if the plan id doesn't exist.
-
403 unless
plan_type=usage-based AND is_admin_managed=0. -
403 unless linked to the partner (
planBelongsToCompany). -
overage_rateread-only (same as create).
Validation — identical rules as Create (same contract-model branching).
Rate limit
- No rate limit.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
planId | integer | Required | Digits only. |
Request body
| Param | In | Type | Required | Description |
|---|---|---|---|---|
planId | path | integer | Yes | Plan ID (route [0-9]+); a usage-based plan owned by the partner. |
Body params are the same as Create plan (Usage-Based only) — including the url_finder_review_site and url_finder_landing_page feature values. The caller must be a main-partner user; sub-partner users are always rejected with 403 (Sub-partners cannot create, edit, or delete plans — plans are managed by your main partner.). On update, omitted status/enforcement_mode fall back to the plan's existing values.
{
"plan_name": "ResponseScribe Pro",
"price": 79.99,
"original_price": 89.99,
"status": "active",
"plan_end_date": "2027-12-31",
"short_info": "Up to 200 responses/month",
"description": "Full AI-powered response service.",
"enforcement_mode": "per-location",
"features": [
{
"feature_name": "ai_response",
"enabled": true,
"hard_stop": true,
"service_limit": 200,
"limit_type": null
},
{
"feature_name": "response_to_past_reviews",
"enabled": true,
"hard_stop": false,
"limit_type": "monthly"
},
{
"feature_name": "per_pull_data",
"enabled": true
}
],
"review_sites": [
{
"review_site_id": 1,
"pull_frequency": "daily",
"pull_interval": 1,
"pull_times": [
"06:00"
],
"pull_days": []
}
]
}Response
200 — Plan updated · 200
200{
"data": {
"data": {
"id": 7,
"plan_name": "ResponseScribe Basic v2",
"price": 59.99,
"original_price": null,
"status": "active",
"description": null,
"plan_end_date": null,
"short_info": null,
"plan_type": "usage-based",
"tier_slug": null,
"enforcement_mode": "per-location",
"is_admin_managed": false,
"created_at": "2026-06-01T09:00:00.000000Z",
"updated_at": "2026-06-19T11:00:00.000000Z",
"deleted_at": null,
"features": [
{
"id": 70,
"plan_id": 7,
"feature_name": "ai_response",
"enabled": true,
"service_limit": 100,
"limit_type": null,
"included_units": null,
"overage_rate": null,
"hard_stop": true,
"created_at": "2026-06-19T11:00:00.000000Z",
"updated_at": "2026-06-19T11:00:00.000000Z",
"deleted_at": null,
"partner_billing_enabled": true
},
{
"id": 71,
"plan_id": 7,
"feature_name": "response_posting",
"enabled": true,
"service_limit": null,
"limit_type": null,
"included_units": null,
"overage_rate": "0.0400",
"hard_stop": false,
"created_at": "2026-06-19T11:00:00.000000Z",
"updated_at": "2026-06-19T11:00:00.000000Z",
"deleted_at": null,
"partner_billing_enabled": true
},
{
"id": 72,
"plan_id": 7,
"feature_name": "per_pull_data",
"enabled": true,
"service_limit": null,
"limit_type": null,
"included_units": null,
"overage_rate": null,
"hard_stop": false,
"created_at": "2026-06-19T11:00:00.000000Z",
"updated_at": "2026-06-19T11:00:00.000000Z",
"deleted_at": null,
"partner_billing_enabled": true
}
],
"plan_review_sites": [
{
"id": 31,
"plan_id": 7,
"review_site_id": 44,
"pull_frequency": "daily",
"pull_interval": 1,
"pull_times": [
"06:00"
],
"pull_days": [],
"created_at": "2026-06-19T11:00:00.000000Z",
"updated_at": "2026-06-19T11:00:00.000000Z",
"deleted_at": null,
"review_site": {
"id": 44,
"name": "Google",
"link": "http://maps.google.com",
"review_site_button": "img-google.png",
"review_site_color": "#3774ee",
"max_rate": 5,
"status": 0,
"show": true,
"use_sau_scrapper": "Y",
"publisher": "maps.google.com",
"auth_type": "oauth",
"scraping_enabled": true,
"posting_enabled": true,
"self_form_enabled": "N",
"email_on_reply": "N",
"deleted_at": null,
"created_at": "2017-01-09T11:33:00.000000Z",
"updated_at": "2020-05-04T02:44:57.000000Z"
}
}
]
}
}
}Errors
| Status | Meaning |
|---|---|
401 | The bearer token is missing, expired or invalid |
403 | No partner resolves, wrong billing model, plan-type mismatch, ownership failure, or the caller is a sub-partner |
404 | Returned if the plan id doesn't exist |
422 | The request failed validation — the response names the fields |
500 | Unexpected server error |
Example request
curl --request POST \
--url "https://production-api.shoutaboutus.com/api/v1/partner/plans/123/update" \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"plan_name": "ResponseScribe Pro", "price": 79.99, "original_price": 89.99, "status": "active", "plan_end_date": "2027-12-31", "short_info": "Up to 200 responses/month", "description": "Full AI-powered response service.", "enforcement_mode": "per-location", "features": [{"feature_name": "ai_response", "enabled": true, "hard_stop": true, "service_limit": 200, "limit_type": null}, {"feature_name": "response_to_past_reviews", "enabled": true, "hard_stop": false, "limit_type": "monthly"}, {"feature_name": "per_pull_data", "enabled": true}], "review_sites": [{"review_site_id": 1, "pull_frequency": "daily", "pull_interval": 1, "pull_times": ["06:00"], "pull_days": []}]}'Updated 10 days ago
