This project has been archived by its maintainers, and is no longer receiving any updates.
Synup SDK
Build local presence automations in minutes — review auto-responders, listings monitors, reputation dashboards, bulk onboarding tools, and more.
Installation
pip install synup-sdk
Quick start: auto-reply to reviews in 10 lines
import synup
client = synup.Synup() # reads SYNUP_API_KEY from env
# Auto-reply to all 4-5 star reviews that haven't been answered
results = client.workflows.auto_reply_to_reviews(
16808,
template="Thanks for the {rating}-star review! We appreciate your support.",
min_rating=4,
)
print(f"Replied to {len(results)} reviews")
Quick start: listings health audit in 3 lines
import synup
client = synup.Synup()
audit = client.workflows.listings_health_audit(16808)
print(f"Health score: {audit.health_score}%")
print(f"Synced: {audit.synced_count}, Issues: {audit.issue_count}")
print(f"Duplicates found: {len(audit.duplicates)}")
Configuration
import synup
# Minimal — reads SYNUP_API_KEY env var
client = synup.Synup()
# Explicit key
client = synup.Synup(api_key="your-api-key")
# With custom config
client = synup.Synup(
api_key="your-api-key",
timeout=300.0, # request timeout in seconds (default: 240)
max_retries=3, # auto-retry on 429/5xx (default: 2)
)
Locations
# List with pagination
page = client.locations.list(first=10)
for loc in page:
print(loc.name, loc.city, loc.stateIso)
# Next page
if page.has_more:
next_page = page.next_page()
# Auto-paginate all
for loc in client.locations.list(first=100).auto_paging_iter():
print(loc.name)
# Retrieve single location
location = client.locations.retrieve(16808)
print(location.name)
# Search
page = client.locations.search("cafe", first=20)
# By IDs, store codes, folder, or tags
locations = client.locations.list_by_ids([16808, 16749])
locations = client.locations.list_by_store_codes(["STORE01", "STORE02"])
locations = client.locations.list_by_folder(folder_name="franchise")
page = client.locations.list_by_tags(["vip", "recent"], first=20)
# Create
result = client.locations.create({
"name": "Acme Inc",
"storeId": "ACME01",
"street": "123 Main St",
"city": "New York",
"stateIso": "NY",
"postalCode": "10001",
"countryIso": "US",
"phone": "5551234567",
})
print(result.success, result.errors)
# Update, archive, activate
client.locations.update({"id": 16808, "phone": "5559876543"})
client.locations.archive([16808])
client.locations.activate([16808])
Reviews
# List reviews with filters
page = client.reviews.list(16808, first=20, rating_filters=[1, 2])
for review in page:
print(review.content, review.rating)
# Auto-paginate all reviews
for review in client.reviews.list(16808, first=50).auto_paging_iter():
print(review.content)
# Respond to a review
client.reviews.respond(interaction_id="uuid-here", content="Thank you!")
# Edit or archive a response
client.reviews.edit_response(review_id="...", response_id="...", content="Updated reply")
client.reviews.archive_response(response_id="...")
# Review analytics
overview = client.reviews.analytics.overview(16808, start_date="2024-01-01")
timeline = client.reviews.analytics.timeline(16808)
sites = client.reviews.analytics.sites_stats(16808)
# Review phrases
phrases = client.reviews.phrases(["TG9jYXRpb246MTY4MDg="], start_date="2024-01-01")
Listings
# Premium, voice, AI, and additional listings
premium = client.listings.premium(16808)
voice = client.listings.voice(16808)
ai = client.listings.ai(16808)
additional = client.listings.additional(16808)
# Duplicates
dupes = client.listings.duplicates(16808)
client.listings.mark_duplicate(16808, ["listing-item-id"])
client.listings.mark_not_duplicate(16808, ["listing-item-id"])
# Connect/disconnect
client.listings.connect(16808, "listing-id", "account-id")
client.listings.disconnect(16808, "GOOGLE")
Analytics
google = client.analytics.google(16808, from_date="2024-01-01")
bing = client.analytics.bing(16808)
facebook = client.analytics.facebook(16808)
# Rankings
timeline = client.analytics.rankings_timeline(
[16808], "2024-01-01", "2024-03-31", ["Google"]
)
histogram = client.analytics.rankings_histogram(
[16808], "2024-01-01", "2024-03-31", ["Google"]
)
Keywords
keywords = client.keywords.list(16808)
performance = client.keywords.performance(16808, from_date="2024-01-01")
created = client.keywords.add(16808, ["plumber", "plumbing near me"])
client.keywords.archive("keyword-id")
Campaigns
campaigns = client.campaigns.list(16808)
result = client.campaigns.create(
16808,
name="Holiday Feedback",
customers=[{"name": "John", "email": "john@example.com"}],
screening=False,
)
client.campaigns.add_customers("campaign-id", [{"name": "Jane", "email": "jane@example.com"}])
Folders
folders = client.folders.list()
tree = client.folders.tree()
client.folders.create("franchise", parent_folder_name="all_franchise")
client.folders.rename("Old Name", "New Name")
client.folders.add_locations("franchise", [16808, 16749])
client.folders.remove_locations([16808])
client.folders.delete("folder-name")
Users
users = client.users.list()
roles = client.users.roles()
result = client.users.create(email="jane@example.com", role_id="...", first_name="Jane")
client.users.update("user-id", first_name="Jane Updated")
client.users.add_locations("user-id", [16808])
client.users.remove_locations("user-id", [16808])
Tags
tags = client.tags.list()
client.tags.add(16808, "vip")
client.tags.remove(16808, "old-tag")
Photos
photos = client.photos.list(16808)
client.photos.add(16808, [{"photo": "https://example.com/img.jpg", "type": "ADDITIONAL"}])
client.photos.remove(16808, ["photo-id"])
client.photos.star(16808, ["media-id"], starred=True)
Connected accounts
accounts = client.connected_accounts.list()
url = client.connected_accounts.connect_google("https://ok.com", "https://err.com")
client.connected_accounts.disconnect_google("account-id")
# OAuth for single location
url = client.connected_accounts.oauth_url(16808, "GOOGLE", "https://ok.com", "https://err.com")
client.connected_accounts.oauth_disconnect(16808, "FACEBOOK")
Grid reports
result = client.grid_reports.create(
location_id=16808,
keywords=["italian restaurant"],
business_name="Chianti",
business_street="No 12, 5th Block",
business_city="Bengaluru",
business_state="Karnataka",
business_country="India",
latitude=12.935216,
longitude=77.619961,
distance=20,
distance_unit="km",
grid_size=3,
)
report = client.grid_reports.retrieve("report-id")
reports = client.grid_reports.list(16808, page_size=20, page=1)
Automations
result = client.automations.temporary_close(
name="Holiday closure",
start_date="2025-12-24",
start_time="18:00:00",
end_date="2025-12-26",
location_id=16808,
)
Account-level
sites = client.plan_sites()
countries = client.countries()
subs = client.subscriptions()
Workflows — pre-built automations
High-level functions that combine multiple API calls into real product features.
# Auto-reply to positive reviews
results = client.workflows.auto_reply_to_reviews(
16808,
template="Thanks for the {rating}-star review!",
min_rating=4,
dry_run=True, # preview without sending
)
# Onboard a location with folder, tags, and keywords in one call
result = client.workflows.onboard_location(
name="Acme Coffee",
street="123 Main St",
city="New York",
state="NY",
postal_code="10001",
country="US",
phone="5551234567",
folder_name="NYC Stores",
tags=["new", "coffee"],
keywords=["coffee shop near me"],
)
# Bulk onboard from CSV
results = client.workflows.bulk_onboard_locations("locations.csv", folder_name="Imported")
# Weekly reputation report
report = client.workflows.weekly_reputation_report(16808)
print(report.review_summary, report.analytics, report.listings_health)
# Listings health audit
audit = client.workflows.listings_health_audit(16808)
print(f"Score: {audit.health_score}%, Issues: {audit.issue_count}")
Error handling
import synup
client = synup.Synup()
try:
client.locations.list()
except synup.AuthenticationError:
print("Invalid API key")
except synup.RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
except synup.NotFoundError:
print("Resource not found")
except synup.ValidationError as e:
print(f"Bad request: {e.response_body}")
except synup.APIError as e:
print(f"API error {e.status_code}: {e.response_body}")
except synup.APIConnectionError:
print("Network error — could not reach API")
Version
Current version: 0.4.0
Metadata
Release files for synup-sdk 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| synup_sdk-0.4.0.tar.gz | 31.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| synup_sdk-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.3 kB
Release files / synup_sdk-0.4.0.tar.gz
| Download URL | synup_sdk-0.4.0.tar.gz |
|---|---|
| Size | 31.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
206fbdac7678521b19fbd4693d938be3e5be9b56839a3e56a94d244d26eafc6a
|
|
BLAKE2b-256 checksum How to use checksums |
146210c707a17aa3f839893c5040b49719758068cddebb796b40e1821adef606
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.4
|
Release files / synup_sdk-0.4.0-py3-none-any.whl
| Download URL | synup_sdk-0.4.0-py3-none-any.whl |
|---|---|
| Size | 31.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
665edee65a7401f586c4f72311c95795256c38e044989cd6ce781da784e3293e
|
|
BLAKE2b-256 checksum How to use checksums |
50fe5c43e1a3b1d3a27e3dde019e38d30275f4ae42d899c8048b444096bf663b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.4
|
Security for synup-sdk 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.