# Reverb OpenCart Integration An OpenCart extension that syncs products, stock, prices, orders, and images between an OpenCart store and a Reverb.com marketplace listing. ## Project Overview **Type:** OpenCart 3.x Extension (with planned OpenCart 4.x compatibility) **Primary Market:** Australia (reverb.com/au) **Sync Direction:** Bidirectional (OpenCart ↔ Reverb) ## Reference Documentation - [Reverb Developer Integrations](https://reverb.com/au/page/integrations) - [Reverb Help: Developer Sections](https://help.reverb.com/hc/en-us/sections/40908931289883) - [OpenCart Extension Development Guide](https://github.com/opencart/opencart/wiki/OpenCart-Extension-Development-Guide) - Reverb API Base URL: `https://api.reverb.com/api/` - Auth: `Authorization: Bearer ` + `Accept-Version: 3.0` headers ## Requirements ### Admin Settings Page The extension must provide an admin panel (`Admin > Extensions > Modules > Reverb`) that allows the store owner to: - Enter and save their personal Reverb.com API token - Select sync direction: One-way (OpenCart → Reverb) or Both-ways (bidirectional) - Select which OpenCart categories are eligible for sync - Manually trigger a full catalogue sync ### Product Page Integration Each product in the OpenCart admin must show a toggle/checkbox to: - Enable or disable syncing that individual product to Reverb - Show the Reverb listing ID and a direct link once the product is listed ### Sync Scope (Bidirectional) | Field | OC → Reverb | Reverb → OC | |--------------|:-----------:|:-----------:| | Title / Name | ✓ | ✓ | | Description | ✓ | ✓ | | Price | ✓ | ✓ | | Stock / Qty | ✓ | ✓ | | Images | ✓ | — | | Orders | — | ✓ | ## Extension Architecture (OpenCart 3.x) ### File Structure ``` upload/ ├── admin/ │ ├── controller/extension/module/reverb/ │ │ └── reverb.php # Admin settings + manual sync trigger │ ├── language/en-gb/extension/module/reverb/ │ │ └── reverb.php # All user-facing strings │ ├── model/extension/module/reverb/ │ │ └── reverb.php # DB interactions (token storage, product map) │ └── view/template/extension/module/reverb/ │ └── reverb.twig # Admin settings form ├── catalog/ │ └── controller/extension/module/reverb/ │ └── reverb.php # Webhook endpoint for Reverb callbacks └── system/ └── library/reverb/ ├── ReverbApi.php # HTTP client wrapping the Reverb REST API ├── ProductMapper.php # Maps OC product fields ↔ Reverb listing fields └── OrderMapper.php # Maps Reverb order payload → OC order format ``` OCMOD patch file (`reverb.ocmod.xml`) injects the per-product toggle into the product edit page without modifying core files. ### Database Tables The extension creates and manages the following tables. **`oc_reverb_product_map`** | Column | Type | Notes | |--------------------|--------------|------------------------------------| | `product_id` | INT | FK to `oc_product` | | `reverb_listing_id`| VARCHAR(64) | Reverb's listing ID once synced | | `sync_enabled` | TINYINT(1) | Per-product on/off toggle | | `last_synced_at` | DATETIME | Timestamp of last successful sync | **`oc_reverb_sync_log`** | Column | Type | Notes | |--------------|---------------------------|-------------------------| | `log_id` | INT AUTO_INCREMENT | | | `product_id` | INT | | | `direction` | ENUM('push','pull') | | | `status` | ENUM('success','error') | | | `message` | TEXT | Error detail or summary | | `created_at` | DATETIME | | API token, sync mode, and category whitelist are stored in OpenCart's native `oc_setting` table via `$this->config` — no custom config table needed. ### Key Design Decisions 1. **API Token storage:** Stored via OpenCart's native settings system (`oc_setting`) with the key prefix `module_reverb_`. Never stored in a raw custom table. 2. **Per-product toggle:** Stored in `oc_reverb_product_map.sync_enabled`; defaults to `0` (disabled) for all products. 3. **Category filter:** Admin selects OpenCart categories; only products in those categories AND with `sync_enabled = 1` are synced. 4. **Webhooks vs polling:** Use Reverb webhooks for real-time order/listing updates; fall back to a scheduled cURL ping (OpenCart cron or system cron calling `catalog/controller/extension/module/reverb/cron`) for stock/price polling. 5. **Image sync:** Upload OpenCart product images to Reverb via `POST /listings/{id}/photos`. Only push images OC → Reverb; do not pull images back. ## Reverb API Essentials Base URL: `https://api.reverb.com/api/` Required headers on every request: ``` Authorization: Bearer Accept-Version: 3.0 Content-Type: application/hal+json ``` Rate limit: ~100 requests/min on the standard plan — batch operations where possible. Key endpoints: | Endpoint | Method | Purpose | | --- | --- | --- | | `/my/listings` | GET | List all existing seller listings | | `/listings` | POST | Create a new listing | | `/listings/{id}` | PUT | Update an existing listing | | `/listings/{id}/end` | PUT | End/delist a listing | | `/listings/{id}/photos` | POST | Upload a photo to a listing | | `/my/orders` | GET | Fetch seller orders | | `/my/orders/{order_number}` | GET | Fetch a single order | | `/webhooks` | POST | Register a webhook endpoint | | `/categories/flat` | GET | Get the full Reverb category tree | ## Sync Flow ### OpenCart → Reverb (triggered on product save event or manual sync) 1. Check product has `sync_enabled = 1` AND is in an allowed category. 2. Map OC product fields to a Reverb listing payload via `ProductMapper::toReverb()`. 3. If `reverb_listing_id` exists in the map → `PUT /listings/{id}`; otherwise → `POST /listings` and store the returned ID. 4. Upload any new/changed images via `POST /listings/{id}/photos`. 5. Update `last_synced_at` and log result in `oc_reverb_sync_log`. ### Reverb → OpenCart (webhook or scheduled poll) 1. Receive webhook POST to `catalog/controller/extension/module/reverb/webhook` (or poll `/my/listings` + `/my/orders`). 2. For listing updates: look up OC product by `reverb_listing_id`, update price / stock / description via model. 3. For new orders: map Reverb order payload to OC order via `OrderMapper::toOpenCart()`, create via `$this->model_checkout_order->addOrder()`. 4. Log result. ## OpenCart 4.x Compatibility Notes - OC 4.x uses PHP namespaces: `namespace Opencart\Admin\Controller\Extension\Module;` - Controllers must extend `\Opencart\System\Engine\Controller` - Template paths and module structure differ from 3.x - Planned approach: ship separate 4.x controller files; share `system/library/reverb/` classes between both versions (they are framework-agnostic) ## Development Guidelines - PHP 7.4+ required; PHP 8.1+ preferred - Use `$this->db->query()` and `$this->db->escape()` for all database access — never raw PDO or unsanitised input - All user-visible strings must be defined in the language file, not hardcoded in controllers or templates - Wrap all Reverb API calls in try/catch; log errors to `oc_reverb_sync_log` rather than surfacing raw exceptions to the UI - The OCMOD XML file is required for injecting the per-product toggle without modifying core OpenCart files - Test against a Reverb sandbox account before connecting a live store