.do
API Reference

ServiceOffering API Reference

Complete API reference for the ServiceOffering type, including marketplace listing methods and properties

The $.ServiceOffering type represents a public marketplace listing for a service. It contains marketing information, pricing, visibility settings, and everything needed to make a service discoverable and purchasable in the marketplace.

Type Definition

// @errors: 7006
interface ServiceOffering extends Thing {
  $type: 'ServiceOffering'
  $id: string
  service: Service
  //         ^^^^^^^
  title: string
  description: string
  longDescription?: string
  images?: string[]
  featured: boolean
  visibility: OfferingVisibility
  //            ^^^^^^^^^^^^^^^^^^^
  pricing: PricingSpecification
  category: string
  tags?: string[]
  rating?: number
  reviewCount?: number
  orderCount?: number
  highlights?: string[]
  benefits?: string[]
  features?: string[]
  testimonials?: Testimonial[]
  callToAction?: CallToAction
  restrictions?: OfferingRestrictions
  seo?: SEOMetadata
  metadata?: OfferingMetadata
}

type OfferingVisibility = 'public' | 'private' | 'unlisted'
//                        ^^^^^^^^

interface Testimonial {
  quote: string
  author: string
  title: string
  company: string
  image?: string
}

interface CallToAction {
  text: string
  url?: string
  action?: string
}

interface OfferingRestrictions {
  regions?: string[]
  industries?: string[]
  minOrderSize?: number
  maxOrderSize?: number
  requiresApproval?: boolean
  //^^^^^^^^^^^^^^^^^
}

interface SEOMetadata {
  metaTitle?: string
  metaDescription?: string
  keywords?: string[]
  slug?: string
}

interface OfferingMetadata {
  createdAt: string
  updatedAt: string
  publishedAt?: string
  lastOrderAt?: string
}

const offering: ServiceOffering = {
  //    ^?
  $type: 'ServiceOffering',
  $id: 'offering-123',
  service: {} as Service,
  title: 'AI SDR Professional',
  description: 'Automated outreach at scale',
  featured: true,
  visibility: 'public',
  pricing: {} as PricingSpecification,
  category: 'sales',
}

Properties

Core Properties

service

  • Type: Service
  • Required: Yes
  • Description: The underlying service being offered
  • Pattern: $.ServiceOffering[id].service -> $.Service[serviceId]
  • Example: $.Service.get('service-123')

title

  • Type: string
  • Required: Yes
  • Description: Marketing title for the offering
  • Example: 'AI-Powered SDR Outreach - Professional Plan'
  • Constraints: 10-200 characters

description

  • Type: string
  • Required: Yes
  • Description: Short marketing description
  • Example: 'Let our AI handle your outreach while you focus on closing deals'
  • Constraints: 50-500 characters

longDescription

  • Type: string
  • Required: No
  • Description: Extended marketing description with full details
  • Format: Markdown supported
  • Example: Multi-paragraph description with formatting

images

  • Type: string[]
  • Required: No
  • Description: Array of image URLs for the offering
  • Example: ['https://cdn.example.com/hero.jpg', 'https://cdn.example.com/screenshot.png']
  • Constraints: Max 10 images, supported formats: JPG, PNG, WebP
  • Type: boolean
  • Required: No
  • Default: false
  • Description: Whether this offering is featured in the marketplace

visibility

  • Type: OfferingVisibility
  • Required: Yes
  • Default: 'public'
  • Values: 'public' | 'private' | 'unlisted'
  • Description: Visibility level of the offering
    • public: Visible to all users in marketplace
    • private: Only visible to specific customers
    • unlisted: Accessible via direct link only

Pricing Properties

pricing

  • Type: PricingSpecification
  • Required: Yes
  • Description: Public pricing for this offering
  • Properties:
    • model: Pricing model type
    • amount: Base price
    • currency: ISO 4217 currency code
    • period: Billing period (for subscriptions)
    • discount: Optional discount information

Marketing Properties

highlights

  • Type: string[]
  • Required: No
  • Description: Key highlights or bullet points
  • Example: ['10x faster than manual outreach', '99% deliverability', '24/7 AI monitoring']

benefits

  • Type: string[]
  • Required: No
  • Description: Customer benefits
  • Example: ['Save 20 hours per week', 'Generate 50% more qualified leads']

features

  • Type: string[]
  • Required: No
  • Description: Feature list
  • Example: ['AI-powered personalization', 'Multi-channel outreach', 'Real-time analytics']

testimonials

  • Type: Testimonial[]
  • Required: No
  • Description: Customer testimonials with author info

callToAction

  • Type: CallToAction
  • Required: No
  • Description: Primary call-to-action button
  • Properties:
    • text: Button text (e.g., 'Start Free Trial')
    • url: External URL (optional)
    • action: Internal action (e.g., 'start-trial')

Computed Properties

rating

  • Type: number
  • Required: No
  • Computed: Yes
  • Description: Average customer rating (0-5)
  • Example: 4.7

reviewCount

  • Type: number
  • Required: No
  • Computed: Yes
  • Description: Total number of reviews
  • Example: 142

orderCount

  • Type: number
  • Required: No
  • Computed: Yes
  • Description: Total number of orders
  • Example: 1547

SEO Properties

seo

  • Type: SEOMetadata
  • Required: No
  • Description: Search engine optimization metadata
  • Properties:
    • metaTitle: SEO title tag
    • metaDescription: SEO meta description
    • keywords: Target keywords
    • slug: URL-friendly slug

Methods

create()

Create a new marketplace offering.

Signature:

$.ServiceOffering.create(config: OfferingConfig): Promise<ServiceOffering>

Parameters:

  • config: Offering configuration object

Returns: Promise resolving to the created ServiceOffering

Example:

const offering = await $.ServiceOffering.create({
  service: $.Service.get('service-id'),
  title: 'AI-Powered SDR Outreach - Professional Plan',
  description: 'Let our AI handle your outreach while you focus on closing deals.',
  longDescription: `
# Transform Your Sales Outreach

Our AI-powered SDR service handles the entire outreach process...

## What You Get
- Personalized messaging for each lead
- Multi-channel outreach (email, LinkedIn, phone)
- Real-time analytics and reporting
  `,
  images: ['https://cdn.example.com/hero.jpg', 'https://cdn.example.com/dashboard.png'],
  featured: true,
  visibility: 'public',
  pricing: {
    model: 'per-lead',
    amount: 5,
    currency: 'USD',
  },
  category: 'sales',
  tags: ['ai', 'sdr', 'outreach', 'b2b'],
})

get()

Retrieve an offering by ID.

Signature:

$.ServiceOffering.get(id: string): Promise<ServiceOffering>

Parameters:

  • id: Offering identifier

Returns: Promise resolving to the ServiceOffering

Example:

const offering = await $.ServiceOffering.get('offering-123')
console.log(offering.title)
console.log(offering.pricing)

list()

List all offerings with optional filtering.

Signature:

$.ServiceOffering.list(filter?: OfferingFilter): Promise<ServiceOffering[]>

Parameters:

  • filter: Optional filter criteria

Returns: Promise resolving to array of ServiceOfferings

Example:

// List all public offerings
const publicOfferings = await $.ServiceOffering.list({
  visibility: 'public',
})

// List featured offerings
const featured = await $.ServiceOffering.list({
  featured: true,
  visibility: 'public',
})

find()

Find offerings matching specific criteria.

Signature:

$.ServiceOffering.find(query: OfferingQuery): Promise<ServiceOffering[]>

Parameters:

  • query: Query object with filter criteria

Returns: Promise resolving to matching ServiceOfferings

Example:

// Find by category
const salesOfferings = await $.ServiceOffering.find({
  category: 'sales',
  visibility: 'public',
})

// Find by service
const serviceOfferings = await $.ServiceOffering.find({
  service: 'service-id',
})

// Complex query with sorting
const topRated = await $.ServiceOffering.find({
  visibility: 'public',
  rating: { $gte: 4.5 },
})
  .sort({ rating: -1 })
  .limit(10)

Full-text search across offerings.

Signature:

$.ServiceOffering.search(query: string, options?: SearchOptions): Promise<ServiceOffering[]>

Parameters:

  • query: Search query string
  • options: Optional search configuration

Returns: Promise resolving to matching ServiceOfferings

Example:

// Simple search
const results = await $.ServiceOffering.search('SDR outreach')

// Search with filters
const results = await $.ServiceOffering.search('content generation', {
  category: 'marketing',
  minRating: 4.0,
  limit: 10,
})

update()

Update offering properties.

Signature:

$.ServiceOffering[id].update(changes: Partial<OfferingConfig>): Promise<ServiceOffering>

Parameters:

  • changes: Object containing properties to update

Returns: Promise resolving to updated ServiceOffering

Example:

// Update title and pricing
await $.ServiceOffering[offeringId].update({
  title: 'Updated Title',
  pricing: {
    model: 'per-lead',
    amount: 4.5,
    currency: 'USD',
  },
})

// Update visibility
await $.ServiceOffering[offeringId].update({
  visibility: 'private',
})

delete()

Delete an offering.

Signature:

$.ServiceOffering[id].delete(): Promise<void>

Returns: Promise resolving when complete

Example:

await $.ServiceOffering[offeringId].delete()

publish()

Publish an offering (set visibility to public).

Signature:

$.ServiceOffering[id].publish(): Promise<ServiceOffering>

Returns: Promise resolving to updated ServiceOffering

Example:

await $.ServiceOffering[offeringId].publish()

unpublish()

Unpublish an offering (set visibility to private).

Signature:

$.ServiceOffering[id].unpublish(): Promise<ServiceOffering>

Returns: Promise resolving to updated ServiceOffering

Example:

await $.ServiceOffering[offeringId].unpublish()

purchase()

Purchase an offering (creates order and initiates execution).

Signature:

$.ServiceOffering[id].purchase(config: PurchaseConfig): Promise<PurchaseResult>

Parameters:

  • config: Purchase configuration

Returns: Promise resolving to purchase result

Example:

const purchase = await $.ServiceOffering[offeringId].purchase({
  customer: $.User.current(),
  params: {
    leads: [{ name: 'John Doe', email: '[email protected]' }],
  },
  payment: {
    method: 'card',
    token: 'tok_visa_4242',
  },
})

console.log(purchase.order)
console.log(purchase.execution)
console.log(purchase.payment)

Property Access

ServiceOfferings support semantic property access:

// Get offering title
const title = await $.ServiceOffering[offeringId].title

// Get pricing
const pricing = await $.ServiceOffering[offeringId].pricing

// Get related service
const service = await $.ServiceOffering[offeringId].service

// Get computed metrics
const rating = await $.ServiceOffering[offeringId].rating
const reviewCount = await $.ServiceOffering[offeringId].reviewCount
const orderCount = await $.ServiceOffering[offeringId].orderCount

Relations

service

Access the underlying service.

Pattern: $.ServiceOffering[id].service -> $.Service[serviceId]

Example:

const offering = await $.ServiceOffering.get('offering-123')
const service = await offering.service
console.log(service.workflow)

orders

Access orders placed for this offering.

Pattern: $.ServiceOffering[id].orders -> $.ServiceOrder[]

Example:

const orders = await $.ServiceOffering[offeringId].orders
console.log(`Total orders: ${orders.length}`)

reviews

Access customer reviews.

Pattern: $.ServiceOffering[id].reviews -> $.Review[]

Example:

const reviews = await $.ServiceOffering[offeringId].reviews
const avgRating = reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length

provider

Access the provider (inherited from service).

Pattern: $.ServiceOffering[id].provider -> $.Organization | $.Person

Example:

const provider = await $.ServiceOffering[offeringId].provider
console.log(provider.name)

Usage Examples

Example 1: Create SDR Offering with Full Marketing

const sdrOffering = await $.ServiceOffering.create({
  service: $.Service.get('sdr-service'),
  title: 'AI-Powered SDR Outreach - Scale Your Pipeline',
  description: 'Automated outreach that sounds human. Book more meetings without hiring.',
  longDescription: `
# Scale Your Sales Pipeline with AI

Stop spending hours on manual outreach. Our AI-powered SDR service handles everything from lead research to personalized messaging.

## How It Works

1. **Upload your lead list** - CSV, CRM sync, or API integration
2. **AI researches each lead** - Company info, recent news, LinkedIn activity
3. **Personalized messages sent** - Via email and LinkedIn
4. **Responses routed to your team** - Real-time notifications
5. **Analytics dashboard tracks everything** - Open rates, response rates, meetings booked

## Results You Can Expect

- **10-15% average response rate** - 3x better than industry average
- **3-5% meeting booking rate** - Qualified meetings, not tire kickers
- **99% email deliverability** - Enterprise-grade infrastructure
- **24/7 automated follow-ups** - Never let a lead go cold

## What's Included

- Unlimited lead research
- Personalized email sequences
- LinkedIn connection requests
- Multi-channel follow-ups
- Real-time analytics
- CRM integration
- Dedicated support

## Perfect For

- B2B SaaS companies
- Sales teams of 5-50 reps
- Outbound-focused organizations
- Companies scaling their pipeline
  `,
  images: [
    'https://cdn.services.do/sdr/hero.jpg',
    'https://cdn.services.do/sdr/dashboard.png',
    'https://cdn.services.do/sdr/analytics.png',
    'https://cdn.services.do/sdr/messages.png',
  ],
  featured: true,
  visibility: 'public',
  pricing: {
    model: 'per-lead',
    amount: 5,
    currency: 'USD',
    discount: {
      type: 'volume',
      tiers: [
        { min: 100, discount: 0.1 },
        { min: 500, discount: 0.2 },
        { min: 1000, discount: 0.3 },
      ],
    },
  },
  category: 'sales',
  tags: ['ai', 'sdr', 'outreach', 'b2b', 'automation'],
  highlights: ['10x faster than manual outreach', '15% average response rate', '99% email deliverability', '24/7 AI monitoring', 'CRM integration included'],
  benefits: [
    'Save 20+ hours per week on prospecting',
    'Generate 50% more pipeline',
    'No hiring or training needed',
    'Scale without adding headcount',
    'Focus on closing, not cold calling',
  ],
  features: [
    'AI-powered personalization',
    'Multi-channel outreach (email + LinkedIn)',
    'Automated follow-up sequences',
    'Real-time analytics dashboard',
    'CRM integration (Salesforce, HubSpot)',
    'A/B testing and optimization',
    'Dedicated account manager',
    '24/7 customer support',
  ],
  testimonials: [
    {
      quote: 'This service 10x-ed our outbound pipeline in just 2 weeks. The personalization is incredible.',
      author: 'Sarah Johnson',
      title: 'VP Sales',
      company: 'TechCorp Inc',
      image: 'https://cdn.services.do/testimonials/sarah.jpg',
    },
    {
      quote: 'We went from 2% to 12% response rate overnight. Game changer for our team.',
      author: 'Mike Chen',
      title: 'Head of Growth',
      company: 'StartupXYZ',
    },
  ],
  callToAction: {
    text: 'Start Free Trial',
    action: 'start-trial',
  },
  restrictions: {
    regions: ['US', 'CA', 'EU', 'UK'],
    industries: ['B2B SaaS', 'Technology', 'Professional Services'],
    minOrderSize: 10,
    requiresApproval: false,
  },
  seo: {
    metaTitle: 'AI SDR Outreach Service - Automate Your Sales Prospecting',
    metaDescription: 'Automate your sales outreach with AI. 10x faster, 15% response rates, no hiring needed. Start your free trial today.',
    keywords: ['ai sdr', 'sales automation', 'outreach service', 'lead generation', 'b2b sales'],
    slug: 'ai-sdr-outreach-professional',
  },
})

Example 2: Create Content Writing Offering

const contentOffering = await $.ServiceOffering.create({
  service: $.Service.get('content-service'),
  title: 'AI Blog Post Writer - Professional Content at Scale',
  description: 'High-quality blog posts written by AI, reviewed by humans. 10x your content output.',
  images: ['https://cdn.services.do/content/hero.jpg'],
  featured: false,
  visibility: 'public',
  pricing: {
    model: 'per-unit',
    amount: 50,
    currency: 'USD',
    discount: {
      type: 'volume',
      tiers: [
        { min: 10, discount: 0.15 },
        { min: 50, discount: 0.25 },
      ],
    },
  },
  category: 'content',
  tags: ['ai', 'content', 'blog', 'writing', 'seo'],
  highlights: ['1000+ word blog posts', 'SEO optimized', 'Human review included', '24-hour turnaround', 'Unlimited revisions'],
  benefits: ['10x your content production', 'Save 80% on content costs', 'Consistent brand voice', 'SEO-friendly content'],
  features: [
    'Topic research',
    'Outline creation',
    'Full blog post writing',
    'Human editing and review',
    'SEO optimization',
    'Image suggestions',
    'Meta descriptions',
    'Internal linking',
  ],
  callToAction: {
    text: 'Order Your First Post',
    action: 'order-now',
  },
})
// Get all featured offerings
const featured = await $.ServiceOffering.find({
  featured: true,
  visibility: 'public',
})

console.log(`Found ${featured.length} featured offerings`)

featured.forEach((offering) => {
  console.log(`${offering.title}: ${offering.rating} stars (${offering.reviewCount} reviews)`)
})

Example 4: Sort Offerings by Popularity

// Get most popular offerings
const popular = await $.ServiceOffering.find({
  visibility: 'public',
})
  .sort({ orderCount: -1 })
  .limit(10)

console.log('Top 10 Most Popular Services:')
popular.forEach((offering, index) => {
  console.log(`${index + 1}. ${offering.title} (${offering.orderCount} orders)`)
})

Example 5: Search Offerings by Keyword

// Search for AI automation services
const results = await $.ServiceOffering.search('ai automation workflow', {
  category: 'automation',
  minRating: 4.0,
  limit: 20,
})

console.log(`Found ${results.length} matching services`)

Example 6: Update Offering Pricing

// Update pricing with volume discount
await $.ServiceOffering[offeringId].update({
  pricing: {
    model: 'per-lead',
    amount: 4.5,
    currency: 'USD',
    discount: {
      type: 'volume',
      tiers: [
        { min: 100, discount: 0.15 },
        { min: 500, discount: 0.25 },
        { min: 1000, discount: 0.35 },
      ],
    },
  },
})

Example 7: Add Testimonial to Offering

// Add a new testimonial
const offering = await $.ServiceOffering.get('offering-id')

await $.ServiceOffering[offering.$id].update({
  testimonials: [
    ...offering.testimonials,
    {
      quote: 'Absolutely transformed our content strategy. Highly recommended!',
      author: 'Jane Smith',
      title: 'Content Director',
      company: 'MarketingCo',
    },
  ],
})

Example 8: Publish/Unpublish Offerings

// Publish an offering
await $.ServiceOffering[offeringId].publish()
console.log('Offering is now public')

// Unpublish temporarily
await $.ServiceOffering[offeringId].unpublish()
console.log('Offering is now private')

Example 9: Create Private Enterprise Offering

const enterpriseOffering = await $.ServiceOffering.create({
  service: $.Service.get('custom-ai-service'),
  title: 'Enterprise AI Automation - Custom Solutions',
  description: 'Custom AI automation solutions tailored for enterprise clients.',
  visibility: 'private',
  pricing: {
    model: 'custom',
    amount: 0,
    currency: 'USD',
  },
  category: 'enterprise',
  tags: ['enterprise', 'custom', 'ai', 'automation'],
  restrictions: {
    requiresApproval: true,
    minOrderSize: 10000,
  },
  callToAction: {
    text: 'Contact Sales',
    action: 'contact-sales',
  },
})

Example 10: Get Offering Analytics

const offering = await $.ServiceOffering.get('offering-id')

// Get comprehensive analytics
const analytics = {
  rating: offering.rating,
  reviewCount: offering.reviewCount,
  orderCount: offering.orderCount,
  orders: await offering.orders,
  reviews: await offering.reviews,
}

// Calculate conversion rate
const views = analytics.orderCount * 10 // Estimate: 1 order per 10 views
const conversionRate = (analytics.orderCount / views) * 100

console.log(`Analytics for ${offering.title}:`)
console.log(`- Rating: ${analytics.rating}/5 (${analytics.reviewCount} reviews)`)
console.log(`- Orders: ${analytics.orderCount}`)
console.log(`- Conversion Rate: ${conversionRate.toFixed(2)}%`)

Example 11: Clone Offering for Different Market

const originalOffering = await $.ServiceOffering.get('original-offering-id')

// Create variation for enterprise market
const enterpriseOffering = await $.ServiceOffering.create({
  ...originalOffering,
  title: `${originalOffering.title} - Enterprise`,
  pricing: {
    ...originalOffering.pricing,
    amount: originalOffering.pricing.amount * 3,
    discount: {
      type: 'volume',
      tiers: [
        { min: 1000, discount: 0.2 },
        { min: 5000, discount: 0.3 },
      ],
    },
  },
  features: [...originalOffering.features, 'Dedicated account manager', 'Custom SLA', 'Priority support', 'White-label option'],
})
// Feature top-rated offerings
const topRated = await $.ServiceOffering.find({
  visibility: 'public',
  rating: { $gte: 4.8 },
})

await Promise.all(topRated.map((offering) => $.ServiceOffering[offering.$id].update({ featured: true })))

console.log(`Featured ${topRated.length} top-rated offerings`)

Events

ServiceOfferings emit the following events:

  • offering.created - Offering was created
  • offering.updated - Offering was updated
  • offering.deleted - Offering was deleted
  • offering.published - Offering was published
  • offering.purchased - Offering was purchased
  • offering.featured - Offering was featured
  • offering.unfeatured - Offering was unfeatured

Example:

import { on } from 'sdk.do'

on.ServiceOffering.created(async (offering) => {
  console.log(`New offering created: ${offering.title}`)
})

on.ServiceOffering.purchased(async ({ offering, order }) => {
  console.log(`${offering.title} was purchased!`)
})

API Endpoints

ServiceOfferings are accessible via REST API:

  • GET /api/offerings - List offerings (public)
  • GET /api/offerings/:id - Get offering details
  • POST /api/offerings - Create offering (requires auth)
  • PUT /api/offerings/:id - Update offering (requires auth)
  • DELETE /api/offerings/:id - Delete offering (requires auth)
  • POST /api/offerings/:id/purchase - Purchase offering
  • GET /api/offerings/featured - Get featured offerings
  • GET /api/offerings/category/:category - Get by category
  • GET /api/offerings/search - Search offerings

Security

  • Public Access: Anyone can view public offerings
  • Private Access: Only authorized users can view private offerings
  • Unlisted Access: Anyone with the direct link can view
  • Modifications: Only service provider can modify

Schema.org Mapping

ServiceOfferings extend Schema.org types:

Property Mappings:

  • name -> title
  • description -> description
  • image -> images
  • offers -> pricing
  • category -> category
  • aggregateRating -> rating and reviewCount

See Also