Estimate the points a product would earn
GET /products/{product_id}/points| Scope | program:read |
| Customer session token | Accepted with the read scope, for the token’s own customer |
| Rate limit class | read (limits) |
| Idempotency key | Not used |
| MCP tool | charm_estimate_product_points |
The number the storefront widget shows on a product page, for headless storefronts: earning rules with the shop’s tax handling, product / collection / tag exclusions, active campaigns and, with customer_id, that customer’s tier multiplier and per-customer bonuses. No Shopify lookup happens — send the unit price in the shop currency and, where the program uses them, the product’s collection_ids and tags. An unknown customer_id gives the anonymous estimate. enabled: false carries a reason (program_disabled, no_points_layer, product_excluded, customer_excluded).
Parameters
Section titled “Parameters”| Name | In | Type | Description |
|---|---|---|---|
product_id | path | string | Shopify product GID (percent-encoded) or the numeric product id. |
price | query | number | Unit price in the shop currency. |
quantity (optional) | query | integer | Units, 1–99. Defaults to 1. |
variant_id (optional) | query | string | Variant GID or numeric id, for variant-level exclusions. |
collection_ids (optional) | query | string | Comma-separated collection GIDs or numeric ids the product belongs to. |
tags (optional) | query | string | Comma-separated product tags, for tag-based exclusions. |
customer_id (optional) | query | string | Customer GID or numeric id; applies their tier multiplier and per-customer bonuses. |
Response 200
Section titled “Response 200”Returns ProductEstimate.
| Field | Type | Description |
|---|---|---|
product_id | string | |
variant_id | string or null | (nullable) |
quantity | integer | |
price | number | The unit price you sent, in the shop currency. |
currency | string or null | (nullable) |
estimate | true | |
enabled | boolean | False when nothing would be earned; see reason. |
reason | string or null: program_disabled, no_points_layer, product_excluded, customer_excluded | (nullable) |
points | integer | Total the purchase would earn. |
base_points | integer | |
bonus_points | integer | |
tier_multiplier | number | (optional) |
campaign_multiplier | number | (optional) |
customer_id | string or null | The customer the estimate was priced for; null for anonymous. (optional, nullable) |
{ "product_id": "8123456789", "variant_id": "44123456789", "quantity": 1, "price": 1, "currency": "EUR", "estimate": true, "enabled": true, "reason": "program_disabled", "points": 120, "base_points": 120, "bonus_points": 120, "tier_multiplier": 1, "campaign_multiplier": 1, "customer_id": "gid://shopify/Customer/7712345"}Example
Section titled “Example”curl -X GET "https://charm.appfleece.app/api/v1/products/<product_id>/points" \ -H "Authorization: Bearer chrm_live_..."Errors
Section titled “Errors”unauthorized · invalid_token · token_expired · insufficient_scope · access_required · not_found · validation_error · rate_limited
Every error body carries code, message, request_id and a doc_url pointing at the matching entry in the error catalog.