Description
XCodeSol Buyback Shop transforms WooCommerce from a product-selling store into a mobile-phone buyback platform. Instead of buying products, customers:
- Select a used phone (manufacturer, model, storage, carrier, variant).
- Answer condition questions.
- Receive an estimated buyback offer.
- Submit the device and receive an inbound shipping label.
- Track the shipment to your warehouse.
- Receive a final offer after inspection.
- Accept and get paid, or reject and receive the device back.
WooCommerce remains the underlying commerce framework: customer accounts, orders, emails, My Account, HPOS, and REST are all used through their official APIs. XCSBC adds a buyback-case layer that tracks the full lifecycle.
External services
This plugin connects to third-party services when the related provider is enabled in the settings screen. These integrations are required for shipping label creation, tracking, payout processing, and webhook validation.
- EasyPost — used for shipping labels, rates, tracking, and webhook verification. Data sent includes shipment addresses, parcel dimensions/weights, order identifiers, tracking numbers, and the signed webhook payload. Terms of service: https://legal.easypost.com/ Privacy policy: https://legal.easypost.com/#privacy-policy
- Shippo — used for shipping labels, postage purchase requests, and shipment tracking. Data sent includes shipping addresses, parcel details, item metadata, and tracking identifiers. Terms of service: https://goshippo.com/terms/ Privacy policy: https://goshippo.com/privacy/
- Stripe Connect — used for payout destination setup, transfer requests, and payout status checks when the merchant enables the Stripe payout flow. Data sent includes payout amounts, destination account data, and merchant identifiers required for transfer processing. Terms of service: https://stripe.com/legal Privacy policy: https://stripe.com/privacy
Key features:
- Buyback-only, mixed-store, and headless/API modes.
- Device catalogue managed entirely through WooCommerce Products (custom “Buyback Device” type, Brands, categories, variations, per-variation buyback pricing).
- Admin-configurable condition questionnaire with per-answer price adjustments.
- Deterministic pricing engine using integer minor-unit currency math.
- Buyback case state machine with full audit history.
- 18 WooCommerce order statuses mapped to the buyback lifecycle.
- “Buyback Submission” payment method (zero customer payment).
- Custom My Account endpoints: dashboard, shipping labels, offers, payouts, returns, support, privacy.
- REST API under /wp-json/xcsbc/v1/.
- Shipping provider integration (EasyPost, Shippo; Mock is restricted to non-production environments).
- Manual payout tracking with an audited finance confirmation workflow.
- Support chat with internal notes.
- Data export/erasure workflows and consent records.
Installation
- Upload the
xcodesol-buyback-shopfolder to/wp-content/plugins/. - Activate the plugin through the Plugins screen.
- Go to WooCommerce Buyback Settings, choose EasyPost or Shippo, configure production credentials and the warehouse address, then enable buyback mode. New installs stay closed until setup is complete.
- Add buyback devices as WooCommerce products (type “Buyback Device”), set brands and variations, and mark them accepted in the Device Info tab.
Finance currently sends customer payouts through the merchant’s approved external payment process, then records them as paid in the Buyback Payouts screen.
Requires WooCommerce 8.0+.
FAQ
-
Does it work with HPOS?
-
Yes. HPOS compatibility is declared via the official WooCommerce feature declaration and all order access goes through WC CRUD (
wc_get_order()). -
Do customers pay anything?
-
No. The default submission model is zero customer payment. The merchant pays the customer after inspection.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“XCodeSol Buyback Shop” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “XCodeSol Buyback Shop” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
2.3.1
- Safety: buyback intake is disabled on fresh installs until the merchant has completed setup.
- Settings: saving the settings page now preserves hidden values and secrets, updates legacy options used by runtime integrations, validates provider selections, and does not reset configured options on reactivation.
- Shipping: production sites cannot use Mock or unknown providers, and provider secrets now read from the documented environment variables.
- Webhooks: EasyPost signatures are verified using HMAC-SHA256 with timestamp freshness checks; Shippo can be authenticated with a per-endpoint URL token.
- Payouts: incomplete Stripe Connect and payout-destination flows are no longer offered as live integrations. Manual payouts can be marked paid by finance with an audited, nonce-protected action.
- Privacy: blank password fields preserve stored shipping credentials.
2.3.0
- Reliability: webhook events are now applied asynchronously by a real job listener (previously the async hook had no consumer and events were applied inline on the webhook request). Each event is claimed atomically before processing, invalid signatures are stored but never applied, a failing event is retried with its error recorded, and the event row now records whether it came from a shipping or payout provider.
- Reliability: every scheduled job runs under a database-backed lock, so overlapping cron ticks can no longer process the same work twice; the WP-Cron fallback now honours each job’s real cadence instead of running everything hourly.
- Fraud: the risk scorer was never called, so fraud score, status and flags were always empty. Submissions are now scored (questionnaire risk, lost/stolen declaration, account age, prior completed cases), stored on the case, surfaced as flags in Fraud Review, and a blocking score routes the case to review.
- Pricing: risk-based deduction is now a real engine input rather than a hardcoded zero, configurable per score point with a cap (off by default, so existing offers are unchanged).
- Pricing: fixed a rule-resolution bug where an unconfigured device or region silently inherited an unrelated rule’s price. A rule now only matches the columns it actually defines.
- Questionnaire: fixed a seeder bug that keyed the second answer of every yes/no question as “no”. “Yes, iCloud locked”, “Yes, Google locked” and “Yes” (reported lost or stolen) therefore overwrote the benign answer, leaving a single mislabelled option — which permanently disabled the iCloud/Google/lost-stolen gates. Existing installs are repaired by a migration.
- Performance: the active questionnaire, pricing rules and settings are cached, and the catalogue no longer re-queries a pricing rule per device.
- Admin: every list screen (cases, payouts, returns, shipments, warehouse, support, fraud, audit) is now paginated instead of silently truncating at 50/100 rows, and the admin REST listings report a total.
- Notifications: email is no longer sent on the triggering request — a slow mail host used to block checkout, chat and label creation. Delivery is queued, burst-prone chat replies are coalesced into one email, and the in-app feed plus unread state are exposed over REST.
- Developer: classes that shared a file with another class were split into PSR-4 files (a strict autoloader could not resolve them standalone); a test now guards one-class-per-file.
2.2.0
- Pricing: percentage adjustments (condition, battery, carrier lock, market, promotion) now compound on the running total instead of all being computed against the base price, matching merchant expectations for stacked discounts.
- Pricing: offers below the configured minimum payout are now reported as blocked with a “below_min_payout” reason instead of silently showing zero.
- Money: added zero-decimal currencies (JPY, KRW) so their offers are no longer inflated a hundredfold by the 2-decimal default.
- Reliability: quote and case number generation now retries on unique-key collisions instead of failing the customer’s request when two submissions race.
- Chat: message dedupe is scoped per conversation (unique index is now conversation_id + client_message_id); a retried message in one thread can no longer be confused with a same-id message in another.
- Webhooks: ingestion now relies on the provider_event_id unique index at insert time, closing a race where two concurrent deliveries of the same event could both be processed.
- Uninstall: with “delete data on uninstall” enabled, cleanup now removes all xcsbc_* options, transients, user meta, scheduled jobs, and the private uploads directory (device photos, documents), not just a fixed option list.
1.0.1
- Support chat messages now record which channel wrote them (customer widget vs staff inbox), so each thread renders as a real left/right conversation on both the customer and the admin side — even when the same account owns the case and manages the shop.
- Staff replies are labelled “Support” for customers; the admin inbox labels every message with the sender’s username plus an Admin or Customer tag.
- Fixed the migration runner: schema migrations were silently skipped on upgrade because the installer stamped the new version before the runner read it.
- Split MessageRepository into its own file so the PSR-4 autoloader resolves it reliably.
1.0.0
- Initial release: buyback case lifecycle, device catalog, questionnaire, pricing engine, quotes, WooCommerce order integration, state machine, REST API, admin dashboard, shipping/payout abstractions, support chat, privacy workflows.