Prisma Reviews / Guides / Junip reviews API in Python
Junip reviews API in Python: private app token, Admin API v2, replies
Junip is a Shopify reviews app with a clean Admin API: two review endpoints (product and store reviews), cursor pages of up to 50, and a reply endpoint that sets, overwrites or clears the merchant’s one answer. Two things to know before you start: the API is on Junip’s Premium plan, and there is no date filter, so incremental syncs work by sorting newest first and stopping early. This guide does it with requests, following Junip’s OpenAPI spec as Prisma’s Junip connector does (in beta, built from the spec). The wider picture of Shopify review apps is on e-commerce reviews API.
pip install requestsCredentials: a private app in Junip Admin (Settings → Apps → Create app) with the reviews:read and reviews:write scopes, its access token, and the store’s https address for links.
1. Page through product and store reviews
import os, requests
from datetime import datetime, timedelta, timezone
API = "https://api.juniphq.com/admin/v2"
H = {"Authorization": f"Bearer {os.environ['JUNIP_ACCESS_TOKEN']}", "Content-Type": "application/json"}
STORE = "https://shop.example.com"
def reviews(kind, since=None):
"""kind: 'product_reviews' or 'store_reviews'. Newest first; stops once older than `since`."""
cursor = None
while True:
params = {"state": "approved", "sort_field": "created_at", "sort_order": "desc", "page_size": 50}
if cursor:
params["page_after"] = cursor
r = requests.get(f"{API}/{kind}", headers=H, params=params, timeout=30)
r.raise_for_status()
body = r.json()
for rev in body.get("data", []):
if since and datetime.fromisoformat(rev["created_at"].replace("Z", "+00:00")) < since:
return
yield rev
cursor = (body.get("meta") or {}).get("after")
if not cursor or not body.get("data"):
return
since = datetime.now(timezone.utc) - timedelta(days=90)
for kind in ("product_reviews", "store_reviews"):
for rev in reviews(kind, since):
c = rev.get("customer") or {}
name = " ".join(x for x in [c.get("first_name"), (c.get("last_name") or "")[:1] and f"{c['last_name'][0]}."] if x)
handle = (rev.get("product") or {}).get("remote_handle")
print(kind, rev["id"], rev.get("rating"), name, rev["created_at"], rev.get("title"), (rev.get("body") or "")[:80], f"{STORE}/products/{handle}" if handle else STORE, "| replied" if (rev.get("response") or "").strip() else "")Fields: id, rating (1 to 5), title, body, response (the merchant’s reply), created_at, updated_at, customer.first_name and last_name (show it as “Artie G.”, as Junip does on the storefront), product.remote_handle (the Shopify product handle, for the link) and store.name. Stay under 2 requests a second per store.
2. Reply, overwrite, clear
rid = rev["id"]
requests.put(f"{API}/product_reviews/{rid}/reply", headers=H, json={"response": "Thank you, Artie. Glad the fit worked out.", "response_alert": False}, timeout=30).raise_for_status()
# the same PUT overwrites; to remove the reply:
requests.put(f"{API}/product_reviews/{rid}/reply", headers=H, json={"response": None}, timeout=30).raise_for_status()response_alert: true emails the customer about the reply; false publishes it quietly. Store reviews use /store_reviews/{id}/reply the same way. Junip doesn’t date the reply, so if you need a timestamp, keep your own or use the review’s updated_at.
3. The same job through Prisma
Prisma connects a Junip store with the private-app token and address (checked before storing, encrypted), reads approved product and store reviews with the 90-day look-back, keeps the reply in the same shape as every other platform, publishes replies with the PUT and reads the review back after a dropped request. One key covers Junip plus Judge.me, Loox, Yotpo, Google and 50+ more.
H = {"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"}
r = requests.get("https://api.prismareviews.com/v1/reviews", headers=H, params={"platform": "junip", "has_reply": "false", "limit": 100}, timeout=30)
for rev in r.json()["data"]:
print(rev["rating"], rev["author"], rev["title"], rev["text"], rev["url"])
requests.post(f"https://api.prismareviews.com/v1/reviews/{rev['id']}/reply", headers=H, json={"text": "Thank you, Artie. Glad the fit worked out."}, timeout=30).raise_for_status()Junip is in beta in Prisma, with replies live. Connection fields: Platforms. A test key returns sample reviews so the code runs now.
FAQ
Which Junip plan includes the Admin API?
Junip’s Admin API is part of its Premium plan. You create a private app in Junip Admin (Settings → Apps → Create app) with the reviews:read and reviews:write scopes and use its access token as a Bearer token.
Can I reply to Junip reviews by API?
Yes. PUT /admin/v2/product_reviews/{id}/reply (or /store_reviews/{id}/reply) with a response field sets or overwrites the one reply; sending null clears it. response_alert controls whether the customer is emailed.
How do I get only new Junip reviews?
There is no date filter. Sort by created_at descending and stop paging when you reach reviews older than your last sync; look back about 90 days so you also catch new replies on recent reviews.
Junip, Judge.me, Loox and Google, one key.
2 locations free. Test keys return sample reviews from every platform.