---
title: "List services"
method: GET
path: "/api/v1/services"
tags: ["Catalog"]
---

# List services

`GET /api/v1/services`

## Request

- Base URL: `https://spoofy.social`
- URL: `https://spoofy.social/api/v1/services`
- Auth: none required

The catalog for programs, a page at a time in a stable order: every service you can order (it lists more than the website shows, which waits for a review), as slim rows — `view=full` for whole services. Without parameters: the first 100 and a `nextCursor`; pass it back as `cursor`, with the same filters, until it is null. Filters combine; a list parameter takes several values, comma separated. Revalidate with the `ETag` (`If-None-Match` → 304).

## Query parameters

- `platform` string
- `metric` string
- `target` string
- `tier` string
- `kind` string
- `country` string
- `q` string
- `limit` integer
- `cursor` string
- `view` 'slim' | 'full'

## Response `200`

One page of the catalog.

- ServicePage
  - `services` union[]: ServiceRow, or Service with `view=full`; in catalog order.
    - union
      - ServiceRow: A service in a list: what choosing one needs. The fields mean what they mean on Service; `description`, `linkHint`, `linkPlatforms`, `form`, `startTime`, `speed`, `delivery`, `packages` and the order form’s `fields` are on GET /api/v1/services/{id} (or `view=full`).
        - `id` integer: Service id — pass it as `service` when quoting or ordering.
        - `platform` string
        - `platformLabel` string
        - `target` string
        - `metric` string
        - `metricLabel` string
        - `tier` string
        - `name` string
        - `kind` 'count' | 'time' | 'manual'
        - `minutes` integer, nullable
        - `minQty` integer
        - `maxQty` integer
        - `pricePer1k` string: Price per 1,000 units. USD as a decimal string.
        - `pricePer1kMicros` string
        - `pricePerUnit` string
        - `cancelable` boolean
        - `startEstimate` string, nullable
        - `country` string, nullable
        - `region` string, nullable
        - `geoGroup` string, nullable
        - `warning` string, nullable
        - `tags` string[]
        - `input` object: The order form without its fields: `shape` default takes only a link and a quantity; any other shape has fields (GET /api/v1/services/{id}).
          - `shape` string
          - `quantity` 'given' | 'count' | 'fixed' | 'per_post'
          - `spread` boolean
      - Service: Something you can buy: one metric on one platform at one quality tier.
        - `id` integer: Service id — pass it as `service` when quoting or ordering.
        - `platform` string
        - `platformLabel` string
        - `target` 'profile' | 'post' | 'video' | 'channel' | 'group' | 'token' | 'site' | 'track' | 'stream' | 'server': What kind of link it takes.
        - `metric` string
        - `metricLabel` string
        - `tier` string
        - `name` string
        - `description` string
        - `linkHint` string: An example of the link this service takes.
        - `minQty` integer
        - `maxQty` integer
        - `kind` 'count' | 'time' | 'manual': `count`: units delivered (followers, views…). `time`: live viewers for `minutes` — `quantity` is how many at most; stopping early refunds the minutes that did not run. `manual`: done-for-you work (a listing), one per order, with a form to fill in (`form`).
        - `minutes` integer, nullable: Time-based services: how long one order runs.
        - `linkPlatforms` string[]: Link platforms it takes besides its own ("*" = any link).
        - `form` object[], nullable: Done-for-you services: what to send as `details` when ordering. Image fields take an upload id (POST /api/v1/uploads).
          - `key` string
          - `kind` 'image' | 'text' | 'textarea' | 'url' | 'email'
          - `label` string
          - `required` boolean
          - `hint` string
          - `max` integer: Text: at most this many characters.
          - `image` object
            - `minWidth` integer
            - `minHeight` integer
            - `ratio` number: Width ÷ height (1 = square).
            - `maxBytes` integer
        - `input` ServiceInput: What a service needs besides a link and a quantity — send the fields in an order’s `inputs`. `shape`: default (link + quantity), package (one, link only), custom_comments (your comments, one per line), mentions_custom_list (accounts to mention), mentions_hashtag, mentions_user_followers, comment_likes, poll (which option), subscription (auto-engagement on future posts).
          - `shape` 'default' | 'package' | 'custom_comments' | 'mentions_custom_list' | 'mentions_hashtag' | 'mentions_user_followers' | 'comment_likes' | 'poll' | 'subscription'
          - `quantity` 'given' | 'count' | 'fixed' | 'per_post': given: you send `quantity` · count: one unit per comment / username sent · fixed: one per order · per_post: subscriptions, charged for max × (posts + old_posts) up front, the unused part refunded when it ends.
          - `fields` object[]
            - `key` string: The key in `inputs`.
            - `kind` 'lines' | 'handles' | 'handle' | 'hashtag' | 'integer' | 'choice' | 'date'
            - `label` string
            - `required` boolean
            - `hint` string
            - `min` integer
            - `max` integer
            - `maxLength` integer: lines: characters per line.
            - `options` integer[]
          - `spread` boolean: The order can be spread over `runs`, `interval` minutes apart.
          - `linksAllowed` boolean: Your text may carry links.
        - `pricePer1k` string: Price per 1,000 units. USD as a decimal string.
        - `pricePer1kMicros` string: Same price in micro-USD (1 USD = 1,000,000), as a string.
        - `pricePerUnit` string: Price of one unit (one viewer for `minutes`, one listing), USD.
        - `cancelable` boolean
        - `startTime` string, nullable
        - `speed` string, nullable
        - `tags` string[]
        - `startEstimate` string, nullable: When delivery usually starts, in words ("Usually starts within 1 h") when we have a real basis (our delivery history, a published average, the service's own words); "Start time varies" otherwise. Null for done-for-you work.
        - `country` string, nullable: ISO 3166-1 alpha-2 code (upper case) when the accounts are from one country, e.g. "US", "BR".
        - `region` 'EU' | 'ASIA' | 'ARAB' | 'AFRICA' | 'LATAM' | 'EN' | 'US+GB' | 'MULTI' | 'null', nullable: When the accounts are from a region rather than one country.
        - `geoGroup` string, nullable: The same for every country / region variant of one service: group by it to offer a country choice.
        - `warning` string, nullable: What to know before buying, in words ("Mixed accounts: quality varies from one account to the next."); null when there is nothing to warn about. On every service, counts can drop after delivery and drops are not replaced.
        - `delivery` object, nullable: The delivery estimate as numbers, to work out the time for any quantity: minutes = startMinutes + quantity ÷ perDay × 1440; without a speed, avgMinutesPer1k × max(1, quantity ÷ 1000). Null until there is an estimate.
          - `startMinutes` integer, nullable: Typical wait before delivery starts.
          - `perDay` integer, nullable: Typical units delivered per day once started.
          - `avgMinutesPer1k` integer, nullable: Typical minutes for 1,000 units, used when the speed is unknown.
          - `source` 'history' | 'supplier' | 'name' | 'similar' | 'history+similar' | 'supplier+similar' | 'name+similar' | 'null', nullable: What the numbers come from: our delivery history, a published average, the service's own words, or (similar) the median of comparable services.
        - `packages` object[]
          - `quantity` integer
          - `price` string: Package total. USD as a decimal string.
          - `eta` string, nullable: Estimated time until fully delivered, in words ("~2 days").
          - `etaMinutes` integer, nullable: The same estimate in minutes.
  - `total` integer: How many services match the filters, on every page.
  - `nextCursor` string, nullable: Pass it as `cursor` (with the same filters) for the next page; null on the last one.

## Other responses

- `400`: A parameter has a value it cannot take.
- `429`: Slow down: too many requests in a short time. Wait `Retry-After` seconds and carry on.
- `500`: Our side failed. Safe to retry.

---

[API](https://skmtc.dev/spoofy/apis/spoofy-api.md) · [All operations](https://skmtc.dev/spoofy/apis/spoofy-api/llms.txt) · [OpenAPI document](https://skmtc.dev/spoofy/apis/spoofy-api/revisions/58adc986f826?raw)
