User guide
Service Marketplace
Looking for what it does rather than how to use it? Read the Service marketplace overview .
The Service Marketplace lets one MSP (the provider) list a service from its catalogue at a wholesale price, and another MSP (the reseller, called the subscriber in the API) subscribe to it, price it for its own clients, add it to its own catalogue, and record sales against it. Every sale becomes a service order carrying the provider’s share, the reseller’s margin and the platform fee. New listings pass through platform review before they go live. This guide covers the MSP portal pages, the platform moderation console, the service-editor path for listing, the AI discovery feature, and the full API.
What it is
An MSP-to-MSP wholesale channel inside Solidlio. Providers publish services they deliver; resellers subscribe and sell them to their own client organizations without those clients ever seeing the marketplace, the wholesale price, or the upstream provider.
It is a separate feature from the escalation provider directory described in SLA and Escalations. That directory hands a ticket to a specialist; the marketplace sells a service. The two share no data.
Concepts
| Term | What it is |
|---|---|
| Listing | A catalogue service offered on the marketplace by a provider. One listing per catalogue service. Carries a title, pitch, category, highlights, tags, three prices, a status, and the platform’s verified / featured flags. |
| Provider | The MSP account that owns the listing and delivers the work. Receives the wholesale cost on every sale. |
| Subscriber (reseller) | The MSP account that subscribed to a listing. Sells the service to its own clients and keeps the difference between its sale price and the wholesale cost. |
| Wholesale cost | providerCostCents. What the reseller pays the provider per sale. Must not exceed the suggested retail price. |
| Suggested retail (MSRP) | msrpCents. The provider’s recommended end-client price. The default subscription price. |
| Price floor | minimumSellCents, optional. No subscription price and no recorded sale may fall below it. Must be at least the wholesale cost. |
| Pricing model | How a reseller prices a subscription: MSRP, PERCENTAGE_MARKUP over cost, FIXED_MARKUP over cost, or CUSTOM. Produces effectiveSellCents. |
| Resold service | A subscription adopted into the reseller’s own catalogue (Add to catalog). It is a normal catalogue service the reseller can grant to a client, priced at effectiveSellCents, and it cannot itself be listed on the marketplace. |
| Sale | A MARKETPLACE_SALE service order. Seller = provider, buyer = reseller, client = the reseller’s client organization or an off-platform client by name. Carries the three-way split, an order number and fulfilment / payment status. |
| Revenue split | Provider share = wholesale cost. Reseller share = sale price − wholesale cost. Platform fee = the configured percentage of the sale price, charged on top to the reseller, not carved out of either share. |
| Review | One per listing per subscribing account, 1–5 stars, with isVerifiedPurchase set when that account has a completed sale on the listing. |
| Verified / Featured | Flags only platform staff can set. Verified shows as a badge; featured shows as a badge and sorts the listing first on browse and on the featured strip. |
| Region | regionAvailability, an availability tag on the listing (NA, EU, APAC, LATAM, GLOBAL). Defaults to NA. It is not a data-residency setting. |
Listing lifecycle
DRAFT ──publish──▶ PENDING_REVIEW ──approve──▶ ACTIVE ◀──publish── PAUSED
▲ │ │ │ ▲
│ │ └──reject (note)────┘ │
└──────withdraw───────┘ └───────pause───────┘
Any status ──suspend (platform)──▶ SUSPENDED ──reinstate (platform)──▶ PAUSED
Unlist from the service editor: ever subscribed ──▶ ARCHIVED ──relist──▶ DRAFT
never subscribed ──▶ deleted
- The first publish goes to
PENDING_REVIEW. Approval stampsapprovedAt; every later publish (resume after a pause, relist after an archive) goes straight toACTIVE. - Rejection returns the listing to
DRAFTwith amoderationNotethe provider sees on My Listings. Resubmitting clears the note. SUSPENDEDis the platform’s state. Publish refuses it and pause refuses it, so a provider cannot pause-then-publish their way out.- Only
ACTIVElistings appear on browse, on the featured strip, and in AI discovery, and onlyACTIVElistings accept subscriptions. A non-active listing’s detail page is a 404 to everyone except its provider and platform staff.
Subscription lifecycle
(subscribe) ──▶ ACTIVE ──cancel──▶ CANCELLED ──subscribe again──▶ ACTIVE
Subscriptions are instant; no provider approval step exists. Cancelling disables the resold catalogue entry; re-subscribing re-enables it and re-syncs its price.
Sale lifecycle
Fulfilment: PENDING → IN_PROGRESS → COMPLETED, or CANCELLED, or DISPUTED. Only the provider may change it. Payment: PENDING → PROCESSING → COMPLETED, or REFUNDED, or FAILED; either side may set it via the API. Fulfilment and payment drive the order’s own status: completing fulfilment completes the order, cancelling fulfilment cancels it and waives its pending platform fees, a refund marks the order REFUNDED.
Roles and permissions
| Action | platform administrator | MSP administrator | MSP technician | organization administrator | power user | CUSTOMER |
|---|---|---|---|---|---|---|
| Browse listings, detail, categories, featured, reviews, fee | ● | ● | ● | — | — | — |
| Create, edit, publish, pause, withdraw a listing | ● | ● | — | — | — | — |
| My Listings dashboard | ● | ● | — | — | — | — |
| Subscribe, change pricing, cancel, add to catalogue | ● | ● | — | — | — | — |
| My Subscriptions and its totals | ● | ● | — | — | — | — |
| Record a sale, update status, complete, link ticket | ● | ● | — | — | — | — |
| Sales ledger and its totals | ● | ● | — | — | — | — |
| Write a review | ● | ● | — | — | — | — |
| Approve, reject, verify, feature, suspend, reinstate | ● | — | — | — | — | — |
Every GET on the marketplace is floored at MSP technician, because listings expose the wholesale price and an MSP’s own clients must not learn their MSP’s margin. Every write, and the three account-financial reads (My Listings dashboard, My Subscriptions, Sales), are floored at MSP administrator. Moderation is platform administrator. A platform administrator passes every floor but still needs an account context to act on tenant routes; without one the response is 401 Account ID required.
There is no public browse.
In the MSP portal navigation, Marketplace shows for all MSP staff; My Listings, Subscriptions and Sales show for MSP administrator and above. Nothing shows in the organization or end-user portals.
Walkthroughs
List a service (provider)
- Marketplace → My Listings (
/msp/marketplace/my-listings) → Create Listing. - Select Service from your catalogue services that are not yet listed. A service you adopted from a marketplace subscription is refused; only services you provide are listable.
- Enter the Listing Title, Description, Category (Managed Services, Security, Cloud, Consulting, Project Work, Support, Backup, Other), Provider cost, MSRP, an optional Minimum sell price, and up to five Highlights.
- Save. The listing is created in
DRAFT. - Press Submit for review. The listing goes to
PENDING_REVIEWand disappears from your editable state until the platform decides. Press Withdraw to take it back toDRAFT. - When approved it becomes
ACTIVEand appears on browse. If rejected, the row shows Returned by review: … with the platform’s note; edit and submit again. - After approval, Pause hides it and Resume re-publishes it instantly, with no second review.
Edits made with Edit Listing take effect immediately, in any status, and do not trigger a new review. Changing a listing’s prices does not recompute existing subscriptions; each subscription keeps its effectiveSellCents until the reseller next changes its pricing.
From the service editor instead. On Services → [service] (/msp/services/[id]), the Marketplace Listing section carries the same cost, MSRP, minimum, pitch and highlights, plus a readiness checklist. Saving with the listing switched on creates or updates the DRAFT listing; switching it off archives a listing that has ever had a subscriber (history and subscriptions kept, gone from browse) and deletes one that never has. Switching it back on returns an archived listing to DRAFT. This path also reads the platform fee live, so the margin preview matches what a sale will record.
Approve or reject a listing (platform)
- Platform → Service Marketplace (
/platform/marketplace). Filter by Pending Review. - Each row shows the provider, cost, MSRP, subscriber and sale counts, and the current flags.
- Approve makes the listing
ACTIVEand stamps its approval, so future pause / resume cycles skip review. Reject asks for a reason, returns the listing toDRAFT, and the provider sees the reason on My Listings. - Verify and Feature toggle the badges on any listing in any status. Suspend pulls a listing (and clears its featured flag); the provider cannot publish out of it. Reinstate returns a suspended listing to
PAUSED, leaving the decision to republish with the provider.
Find and subscribe to a service (reseller)
- Marketplace (
/msp/marketplace). Search by keyword, or filter by category and region. Cards show the provider, rating, wholesale cost, MSRP, the margin between them, and how many MSPs subscribe. Verified and featured badges appear where the platform set them. - Optionally switch on AI Recommendations. Solidlio reads your enabled catalogue services and the live listings (yours excluded) and returns up to a handful of recommendations with a match score, reasons, estimated demand and a revenue estimate, plus the capability gaps it noticed. Each run spends one AI credit and the result is cached for five minutes. If the analysis cannot run, the panel says so and shows no scores rather than inventing them.
- Open a listing (
/msp/marketplace/[listingId]). Its three tabs are Overview, Reviews and Provider Info. The page shows the pitch, highlights, certifications, the provider, reviews, and a revenue preview at MSRP and at the floor, using the platform fee currently configured. - Subscribe to Service. Pick a Pricing Model: MSRP, percentage markup over cost, fixed markup over cost, or a custom price. The dialog shows your effective sell price and split as you type, and the button stays disabled while the price is below the provider’s floor.
- After subscribing the page shows Subscribed, your effective price, and a Manage subscription link. You cannot subscribe to your own listing or subscribe twice; a cancelled subscription shows Resubscribe.
Add the service to your catalogue and grant it to a client
- Marketplace → Subscriptions (
/msp/marketplace/subscriptions). Each row shows the provider, your pricing model and effective price, the wholesale cost, your sales count and revenue, and the subscription’s status. - Change pricing inline (Pricing Model, markup percent, markup amount or custom price). The floor still applies. Saving re-syncs the price on your resold catalogue entry.
- Press Add to catalog. A catalogue service is created in your account, named after the listing and priced at your effective sell price. If your catalogue already offers that same platform service, adoption is refused with a conflict rather than merged. Once adopted, the row shows In your catalog with a link to the service.
- The client sees it on its own Services list at your price, with no reference to the marketplace or the provider.
- The resold service’s price is owned by the subscription. Editing its price in the service editor is refused; change the subscription instead. It also cannot be listed on the marketplace.
Cancel subscription disables the resold catalogue entry so it drops out of client-facing pickers. Re-subscribing re-enables it.
Record a sale and fulfil it
- On Subscriptions, press Record sale on the subscription. Choose a client organization you service from the list, or leave it as an off-platform client and enter a name and email. Enter the Sale price; it must be at least the listing’s floor.
- The sale is created as a service order, already approved, with an order number, the three-way split, and its platform-fee ledger rows. Both MSPs can open it under Billing → Orders (
/msp/billing/orders/[id]). - Marketplace → Sales (
/msp/marketplace/sales) shows the ledger. Toggle between your purchases as a reseller (tile: Your Margin) and your sales as a provider (tile: Your Revenue). The tiles are whole-account totals, not the current page. - As the provider: press Start Work (
PENDING → IN_PROGRESS) and later Complete. Completing stamps the completion time and completes the order. - Either side can Link Ticket by ticket id. The ticket must be in an organization your account can reach; once linked, the row shows the ticket number and subject and the assets attached to that ticket.
- If the sale named a client organization, the reseller’s invoice is raised from it on the nightly service-order invoicing run, in the reseller’s numbering and as a draft the client cannot yet see. Sales recorded against an off-platform client (name only) are not invoiced automatically.
Review a listing
On the listing’s Reviews tab, subscribers (past or present) see Write a review: a 1–5 rating, an optional title and body. One review per account per listing. The review is marked a verified purchase when the account has a completed sale on that listing. The provider cannot review its own listing, and an account that never subscribed is refused. Reviews cannot be edited or deleted once posted.
Configuration
| Setting | Where | Effect, and what happens if unset |
|---|---|---|
| Plan transaction fee | Per plan, in basis points | A second ledger row, “Platform Transaction Fee”, recorded on each sale when the reseller’s plan carries one. Zero when the plan sets none. |
| Wholesale cost, MSRP, minimum sell price | Per listing | Cost ≤ MSRP and minimum ≥ cost are enforced on create, update and the service editor. No minimum → resellers may price down to the wholesale cost. |
| Category | Per listing | One of the eight UI categories, or any string via the API. Unset → the listing shows as Uncategorized and does not appear under any category filter. |
| Highlights | Per listing | Up to 5 in the My Listings dialog, up to 20 via the service editor. Shown on the card and detail page. |
| Tags | Per listing, API and service editor only | Lowercased on write; searchable as whole words and filterable by tags=. The service editor writes the service’s target industries as tags. |
| Region availability | Per listing, API only | Defaults to ["NA"]. The browse Region filter matches this field, so a listing only appears under Europe, Asia Pacific, Latin America or Global if it was set by API. |
| Provider display name, bio, certifications, target audience | Per listing, API only | Display name falls back to the account name. Certifications show on the card and detail page when present. |
| Pricing model | Per subscription | MSRP (default), PERCENTAGE_MARKUP (cost × (1 + %/100), rounded), FIXED_MARKUP (cost + amount), CUSTOM (the amount, or MSRP when blank). Floor enforced on all four. |
| AI credits | Per plan (maxAiCredits), metered per calendar month | Each discovery run costs 1 credit. Over the allowance → 402 AI_CREDIT_LIMIT_EXCEEDED. Free 50, Starter 1,000, Growth 2,000, Scale 3,500, Enterprise unlimited. |
Plan tiers
The marketplace routes carry no plan gate and the navigation entries are gated by role only. Every capability in this guide is available on every MSP tier, including Free. The single tier-dependent limit is the monthly AI credit allowance that AI discovery draws on (see the table above). The marketplace has no organization-portal surface, so end-customer tiers do not apply.
Limits and known behaviour
- How the provider gets paid. Every sale books a provider payable (
MarketplaceSettlement) for the listing’s wholesale cost. It becomes payable only when both legs complete — the work is delivered AND the reseller has actually paid — and is then swept into the same Stripe Connect payout run that pays store sales, net of the same reserve withholding. An MSP that both sells hardware and delivers marketplace work is paid once, in one transfer. A dispute holds the payable where it is; a refund writes it off. The Sales page shows the state per sale in the provider view. - Who may move payment status. Both sides can, except
COMPLETEDandREFUNDED, which are the provider’s alone — those two are what make a real transfer eligible.DISPUTEDis the buyer’s to raise; the provider reopens the work to clear it. - Invoicing. A sale to a client organization is invoiced immediately when it is recorded; the nightly
service-order-invoicingjob is the recovery path for one that could not be (billing unreachable, or a tax hold). A sale to an off-platform client has no organization to invoice and is never invoiced automatically — the sale response says so rather than leaving a reseller waiting for an invoice that is not coming. - Notifications and webhooks. Listing approved and rejected, a new subscription, a recorded sale and a completed fulfilment raise an in-app notification to the side that needs it, and dispatch a webhook of the same name to the receiving account’s organizations. A provider is also notified when a payout including their settlements leaves.
- Subscriptions. Subscribing is instant — there is no provider approval of subscribers, and
PENDINGis an unused state. A reseller may pause and resume a subscription, which keeps the agreed pricing and disables the adopted catalogue entry meanwhile.SUSPENDEDis the platform’s: suspending a listing suspends every subscription on it, and reinstating restores them. - Listing edits re-enter review and reprice subscribers. Changing a live listing’s title, description or price sends it back to
PENDING_REVIEW(the response saysreReviewRequired: true) and recomputes every live subscription’s sell price. A reseller on a CUSTOM price keeps their own number, but it is lifted to the listing’s minimum if it now falls below it. - One of each. One listing per catalogue service, one subscription per listing per account, one review per listing per account. A reviewer may edit or remove their own review.
- No delete route for a listing. Unlist from the service editor: archived if it ever had a subscriber, deleted if it never did.
triageandgenerate-responseremain integration-only: they exist for a PSA calling in and have no first-party screen. Every fallback branch is now labelled where it is rendered, and the branches themselves no longer invent specifics — an unavailable skill-gap analysis returns no gaps rather than a made-up capability assessment, and an unavailable provider match is ranked by rating and says so.- Moderation writes to the audit log. Approve, reject, suspend, reinstate, a flag change and an edit that re-enters review all write audit rows against the provider’s account, alongside
approvedAtandmoderationNoteon the listing. - Browse caps. 100 listings per page; the detail page embeds the 10 most recent reviews; AI discovery considers at most 50 listings. Tag search matches the whole lowercase tag.
- A resold service is locked. It cannot be listed, and its price is changed only through the subscription.
- Adoption can conflict. Because a catalogue holds one entry per platform service, an account that already offers the same platform service cannot also adopt it from the marketplace; resolve the conflict deliberately rather than expecting a merge.
Troubleshooting
| Message | Cause |
|---|---|
401 Account ID required | The request carried no account context. A platform administrator hits this on tenant routes without one. |
403 on browse | The caller is below MSP technician (an org or customer role), or anonymous. There is no public browse. |
403 on My Listings, Subscriptions or Sales | These financial reads are floored at MSP administrator; a technician can browse but not open them. |
Provider cost cannot exceed MSRP | Wholesale cost above the suggested retail price, on create or on the values an update would produce. |
Minimum sell price cannot be less than provider cost | Floor set below the wholesale cost. |
This service already has a marketplace listing | One listing per catalogue service. Edit the existing one. |
A service adopted from a marketplace subscription cannot itself be listed on the marketplace | The selected service is a resold entry from a subscription. |
Listing is already awaiting platform review | Publish pressed twice while PENDING_REVIEW. Wait for the decision or withdraw. |
Cannot publish a suspended listing | The platform suspended it. Only the platform can reinstate. |
Only an active listing can be paused | Pause is ACTIVE → PAUSED only; a pending submission is withdrawn instead. |
Listing is not awaiting review | Withdraw, approve or reject called on a listing that is not PENDING_REVIEW. |
Listing detail returns 404 for an id you were given | The listing is not ACTIVE and you are neither its provider nor platform staff. |
Cannot subscribe to inactive listing | The listing is draft, pending, paused, suspended or archived. |
Cannot subscribe to your own listing | Providers cannot resell their own listing. |
Already subscribed to this listing | An active subscription exists. Change its pricing instead. |
Sell price (X) cannot be less than minimum (Y) | The pricing model produced a price below the provider’s floor. Values are in cents. |
Subscription is already cancelled | Cancel pressed twice. |
Only an active subscription can be added to your catalog | Re-subscribe first. |
This subscription is already in your catalog | Adoption already happened; follow the In your catalog link. |
Your catalog already offers this platform service — it cannot also be adopted from the marketplace | Your catalogue already has an entry for the same platform service. |
This service's price is set by its marketplace subscription — update the subscription's pricing instead | Price edit attempted on a resold service in the service editor. |
404 Active subscription | Recording a sale on a subscription that is cancelled or not yours. |
Sale price cannot be less than minimum (Y) | The recorded sale price is below the listing’s floor. |
clientOrganizationId must be an organization your account services | The organization is not one of yours or a managed client’s, or does not exist. |
ticketId must be a ticket in an organization your account services | The ticket does not exist or belongs to a tenant you cannot reach. |
Only the provider can update fulfillment status | The reseller tried to change fulfilment to something other than DISPUTED, which is the one they may set. |
Only the provider can confirm a payment as received or refunded | The buyer tried to set COMPLETED or REFUNDED. Those two make a real transfer eligible; use PROCESSING to say it was sent. |
This subscription was suspended by the platform and cannot be resumed here | The listing was suspended. Resume becomes available again when the platform reinstates it. |
The listing is not live, so the subscription cannot be resumed yet | The provider has the listing paused or back in review. |
Sale is already completed | Complete pressed twice. |
You cannot review your own listing | Providers cannot review themselves. |
Only accounts that have subscribed to this listing can review it | The account has never held a subscription to this listing. |
You have already reviewed this listing | One review per account per listing. Edit or remove the existing one instead. |
Provide isVerified and/or isFeatured | The moderation flag update had an empty body. |
Listing is already suspended / Listing is not suspended | Suspend or reinstate called in the wrong state. |
402 AI_CREDIT_LIMIT_EXCEEDED | The account’s monthly AI credit allowance is spent; discovery stops until the 1st or credits are bought. |
AI panel: The AI analysis is unavailable right now, so this request was not analyzed. | The model call failed. No scores are invented; try again later. |
| The Region filter returns nothing | Listings default to NA and the region can only be set by API. |