synup-sdk 0.1.2
Python SDK for the Synup API
Requires Python: >=3.8

# Synup SDK

## Installation

```bash
pip install synup-sdk
```

For local development from the engineering-scripts:

```bash
pip install -e synup-sdk
```

## Configuration

Create a client with your API key. You can generate API keys from your Synup workspace: **Settings → Integrations → Generate**.

```python
from synup import SynupClient

client = SynupClient(api_key="YOUR_API_KEY")
```

Optional: use a custom base URL (default is `https://api.synup.com`):

```python
client = SynupClient(api_key="YOUR_API_KEY", base_url="https://api.synup.com")
```

## Fetch all locations

### Single page (with pagination)

Get one page of locations and use the returned cursors to paginate:

```python
result = client.fetch_all_locations(first=10)

# List of location dicts
locations = result["locations"]

# Pagination info
page_info = result["page_info"]
# page_info["has_next_page"], page_info["has_previous_page"]
# page_info["start_cursor"], page_info["end_cursor"]

# Next page
if page_info["has_next_page"]:
    next_result = client.fetch_all_locations(first=10, after=page_info["end_cursor"])
```

### All locations (auto-paginate)

Fetch every location in one call; the SDK will follow cursors until all are retrieved:

```python
all_locations = client.fetch_all_locations(fetch_all=True)
# all_locations is a list of location dicts
```

Optional: set page size when using `fetch_all=True` (default is 100):

```python
all_locations = client.fetch_all_locations(fetch_all=True, page_size=50)
```

## Search and filter locations

You can fetch locations by **location ID**, **store code**, **name** (search), **folder**, or **tags**.

### By location IDs

You can pass **numeric IDs** (e.g. `16808`) or **base64-encoded IDs** (e.g. `"TG9jYXRpb246MTY4MDg="`). Numeric IDs are encoded as `Location:{id}` under the hood.

```python
# Using numeric IDs (recommended)
locations = client.fetch_locations_by_ids([16808, 16749])

# Using base64-encoded IDs (also supported)
locations = client.fetch_locations_by_ids(["TG9jYXRpb246MTY4MDg=", "TG9jYXRpb246MTY3NDk="])
```

### By store codes

```python
locations = client.fetch_locations_by_store_codes(["STORE01", "STORE02"])
```

### By name (search)

Searches location name, street address, and store_id by default. Optional `fields` limits search to specific fields (e.g. `["store_id"]`, `["name"]`).

```python
# One page
result = client.search_locations("cafe", first=10)
locations = result["locations"]
page_info = result["page_info"]

# All matches (auto-paginate)
all_matches = client.search_locations("cafe", fetch_all=True)
```

### By folder

Fetch all locations under a folder (and its subfolders). Use either folder ID or folder name.

```python
# By folder name
locations = client.fetch_locations_by_folder(folder_name="franchise")

# By folder ID (UUID)
locations = client.fetch_locations_by_folder(folder_id="67049f29-3bc6-4e82-875b-02159b4b1fea")
```

### By tags

Fetch locations that have any of the given tags.

```python
# One page
result = client.fetch_locations_by_tags(["recent", "vip"], first=10)

# All (auto-paginate)
locations = client.fetch_locations_by_tags(["recent"], fetch_all=True)

# Only active
locations = client.fetch_locations_by_tags(["recent"], archived=False, fetch_all=True)
```

## Listings for a location

All listing methods accept a **location ID** as numeric (e.g. `16808`) or base64-encoded; numeric IDs are encoded automatically.

### Premium listings

```python
listings = client.fetch_premium_listings(16808)
# List of dicts: id, site, syncStatus, displayStatus, listingUrl, etc.
```

### Voice assistant listings (Google, Alexa, Siri, etc.)

```python
listings = client.fetch_voice_listings(16808)
# name, voiceIdentifier, syncStatus, etc.
```

## Errors

On non-2xx API responses, the client raises `SynupAPIError`:

```python
from synup import SynupClient, SynupAPIError

client = SynupClient(api_key="...")
try:
    client.fetch_all_locations()
except SynupAPIError as e:
    print(e.status_code, e.response_body)
```

## Version

Current version: 0.1.2