Rate Limits & Usage
Share a Wish meters two different things. Wishlist actions are the billing unit of every plan. Per-key rate limits are a technical safeguard reported in response headers. Rate limits never reject requests (there is no 429). Above the monthly action quota, paid plans keep working and pay per additional action (overage); the Free plan is paused at 100% and POST /widget/save answers 402 usage_limit_reached until the next calendar month or an upgrade.
Wishlist actions — the billing unit
One value unit for all shop plans. An action is one of:
| Action | Counted when | Deduplication |
|---|---|---|
save | A product is saved successfully via the widget or a hosted page (/widget/save, /hosted/save). | One per successful save. |
share | A list that contains your products is made public. | One per list and calendar day. |
list_view | A public hosted list containing your products is viewed. | One per list, viewer and 10-minute window. |
Actions are attributed to the partner that supplied the most recently added item of a list. The metering period is the current calendar month (UTC). API calls themselves — including POST /widget/init — are not a pricing dimension.
Per-plan limits
| Plan | Price / month | Included wishlist actions / month | Overage per extra action | Webhooks | Server keys |
|---|---|---|---|---|---|
| Free | 0 € | 200 | — (hard stop: saves are rejected with 402) | no | no |
| Starter | 19 € | 2,000 | 2.5 ct | no | no |
| Growth | 49 € | 15,000 | 1.0 ct | yes | no |
| Scale | 99 € | 60,000 | 0.5 ct | yes | yes |
| Enterprise | individual | individual (treated as unlimited) | individual | yes | yes |
Test keys (pk_test_…) can be created on every plan. The plan is the same whether you subscribe through the Partner Portal or through Shopify billing (see Shopify plans).
Overage & Free-plan hard stop
Paid plans (Starter, Growth, Scale): nothing is switched off at 100%. Every wishlist action above the included quota is billed at the plan's per-action overage rate (Starter 2.5 ct, Growth 1.0 ct, Scale 0.5 ct) at the end of the calendar month. An upgrade is always cheaper than sustained overage: Growth beats Starter from 1,200 actions over the limit, Scale beats Growth from 5,000. Enterprise has an individual quota and rate.
Free plan: 200 actions per calendar month, no overage. At 100% the wishlist is paused: POST /widget/save (and the hosted save page) reject further saves with HTTP 402 until the next calendar month starts or the partner upgrades. Shares and list views are still counted but not blocked.
HTTP/1.1 402 Payment Required
{
"error": "usage_limit_reached",
"message": "Monthly wishlist-action limit of the Free plan reached.",
"plan": "free",
"actions_limit": 200,
"upgrade_url": "https://partner.shareawish.shop/subscription"
}
Handle 402 like a soft failure: show the end customer a friendly "wishlist is paused" notice, do not retry automatically. The hosted save dialog (shareawish.shop/save), which the Save Button SDK opens, already does this — SDK integrations need no extra code; only direct POST /widget/save callers have to handle the status themselves.
80% / 100% notifications
After each recorded action the API compares the month's total with the plan limit. At 80% (USAGE_WARNING_THRESHOLD) and at 100% (USAGE_LIMIT_THRESHOLD) the partner receives one e-mail per threshold and period, and the Partner Portal shows a warning or upgrade banner. Notifications are deduplicated per partner, period and threshold. On paid plans the excess is visible as overage in the /widget/init response and as overage actions and cost in the portal; on Free the portal shows the paused state. Plans without a finite limit (Enterprise) never trigger notifications.
Response headers
Wishlist-action usage on POST /widget/init
| Header | Meaning |
|---|---|
X-Usage-Total | Wishlist actions recorded for the partner this calendar month. |
X-Usage-Limit | Included actions of the plan. |
X-Usage-Remaining | max(0, limit − total). |
The JSON body of the same response carries overage: true once the total exceeds the limit. These headers are informational; enforcement happens only on POST /widget/save for the Free plan (402, see above).
Per-key rate-limit headers on /widget/*, /hosted/*, /shops/*, /baskets/*, /products/*
A middleware resolves your API key from the Authorization: Bearer pk_… header or the widget token, calls the rate-limit function, increments a per-key counter and sets these headers. The values are informational: a request over the per-minute limit is not rejected and there is no 429. Billing happens on wishlist actions, not on requests. If the key cannot be resolved (e.g. an unauthenticated public list read) the headers are absent.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests per minute allowed for the key's plan. |
X-RateLimit-Remaining | Remaining requests in the current minute (never below 0; informational). |
X-RateLimit-Reset | ISO timestamp when the minute window resets. |
X-Usage-Month | Requests counted for this key in the current calendar month. |
X-Usage-Limit | Included monthly requests of the key's plan. |
X-Usage-Overage | Overage amount accrued this month. |
Note the name clash: X-Usage-Limit on /widget/init is the plan's wishlist-action limit; on the other routes it is the per-key request allowance of the legacy API-call model. The rate-limit function skips OPTIONS preflights and the /health and /analytics/* paths.
Checking your usage
- Partner Portal → Subscription shows used / included actions, a breakdown by save / share / list view, the warning level and the period.
GET /me/usage(portal user token) returns{ plan, plan_name, actions_used, actions_limit, period_start, period_end, breakdown, percent, level, trial_days }wherelevelisok,warning(≥ 80%) orexceeded(≥ 100%) — plus the overage fieldshard_limit,overage_per_action_minor(cents,nullon Free / Enterprise),overage_actions,overage_cost_minor,next_plan,upgrade_cheaper_from_actionsandblocked(Free plan paused).GET /api-usage/{apiKeyId}(authenticate with the key itself) returns the per-key request counters and the key's plan limits used for theX-RateLimit-*headers.
FAQ
Will my integration break when I hit the limit?
Not on a paid plan: the API never returns 429, the widget keeps working at 100% and every additional wishlist action is billed as overage (Starter 2.5 ct, Growth 1.0 ct, Scale 0.5 ct per action). On the Free plan saving pauses at 100%: POST /widget/save answers 402 usage_limit_reached until the next calendar month or an upgrade. You get an e-mail at 80% and 100% of the quota and an upgrade banner in the Partner Portal.
What does 402 usage_limit_reached mean?
A Free-plan partner has used its 200 wishlist actions for the calendar month. POST /widget/save rejects further saves with HTTP 402 and the body { error: 'usage_limit_reached', message, plan: 'free', actions_limit, upgrade_url }. Show the end customer a friendly "wishlist paused" notice, do not retry automatically. Paid plans never receive this error; they pay per extra action instead.
Does POST /widget/init count against my quota?
No. Only saves, shares and hosted list views are wishlist actions. Init calls are logged for analytics and the per-key request counters but are not billed.
Do test keys count?
Test keys are available on every plan and their requests are counted by the per-key rate-limit counters. Saves made with a test key are flagged as test traffic in analytics.