《独立开发者的商业指南·合同、应收与风险》9.1 直销、代理、经销的选择

同一笔 8,500 美元的项目,走直销、代理、经销或平台,净得分别是 8,075、3,825、5,100 和 5,950 美元。本节用 Nord 的 55% 转介绍、Tidecast 的 30% 平台分成和 LedgerLite 的直销毛利,算清四种渠道的单笔净得、可控性与所需销量倍数。

以下情境为教学假设,人物与数字不代表经核实的真实案例。

渠道选择经常被写成一道立场题:直销最赚钱,平台最省事,代理最快起量。三个说法都只对一半。渠道真正改变的,是同一笔收入在厂商、渠道和终端客户之间怎么分,以及厂商还剩下多少定价权、客户关系和数据。

这一节把渠道拆成四种结构:直销、代理、经销、平台。然后用一笔 8,500 美元的项目,把四种结构换算成可比较的净得。8,500 美元是本节的教学假设,不是案例事实;案例事实只提供三个锚点:Nord 的转介绍分成 55%、Tidecast 的平台分成 30%、LedgerLite 的直销毛利 84.2%。

四个渠道,四种抽成方式

四个渠道的差别,先看钱怎么走。

渠道谁向客户收钱抽成方式教学抽成8,500 美元净得收入可控性
直销 direct厂商直接收支付处理费5%$8,075高:定价、客户、数据都在手里
平台 platform平台代收平台分成30%$5,950中:上架与产品可控,价格和客户数据受限
经销 distributor经销商买断再售进货折扣40%$5,100低:终端价格与客户归经销商
代理 agent介绍方带来成交成交佣金55%$3,825最低:关系、议价、复购都归介绍方

直销是厂商自己完成获客、签约、收款和交付。它的渠道成本最低,但销售动作最重。LedgerLite 的支付费是 12,000 美元,占收入 240,240 美元的 5.0%,这就是直销渠道里最容易被看见的一层抽成;云、支持和获客成本还在后面。

平台是平台代收,按成交额抽成。Tidecast 在 Steam 上的分成是 30%,平台负责曝光、支付和部分售后,厂商让出的是 30% 的收入和一部分定价权。平台上架不等于厂商能控制促销节奏,折扣、捆绑和区域定价通常要服从平台规则。

经销是经销商先买断,再卖给终端客户。厂商在发货时确认一笔销售收入,按 40% 的进货折扣计算,8,500 美元的项目只收到 5,100 美元。好处是库存和信用风险转移给经销商,坏处是终端价格、客户名单和复购节奏都不在厂商手里。

代理是介绍方带来成交,厂商按成交额付佣金。Nord 的转介绍安排是 55%,一笔 8,500 美元的项目,厂商净得 3,825 美元。代理不承担交付,也不一定承担售后;它卖的是关系和信任,因此分成比例通常最高。

这四种抽成比例是本节的教学假设,不是市场报价。真实合同里,平台分成可能按品类和地区变化,经销折扣可能附带返点,代理佣金可能按新客、续约、增购分档。比例可以变,但结构不变:谁离客户更近,谁拿走的比例更高;厂商省下的动作越多,留下的控制越少。

同一笔 8,500 美元,四种净得

把同一笔 8,500 美元的项目放进四种渠道,净得分别是:

直销:8,500 × 95% = 8,075 美元

平台:8,500 × 70% = 5,950 美元

经销:8,500 × 60% = 5,100 美元

代理:8,500 × 45% = 3,825 美元

排序是直销、平台、经销、代理。直销比代理多 4,250 美元,是代理净得的 111.1%;直销净得是代理净得的 211.1%。平台比代理多 2,125 美元,经销比代理多 1,275 美元。渠道越省力,净得越低,这个方向在四种结构里是一致的。

但净得低不等于渠道差。代理可能带来厂商自己够不到的客户,平台可能带来自然流量,经销商可能覆盖一个厂商没有团队的区域。比较渠道时,不能只问“同一笔收入我留多少”,还要问“这个渠道能带来多少笔我本来拿不到的收入”。

把这个问题换算成一个销量倍数:要匹配一笔直销的净得,其他渠道需要多少笔?

渠道单笔净得匹配 1 笔直销所需笔数说明
平台$5,9501.36平台多带来 36% 的成交,就打平
经销$5,1001.58经销多带来 58% 的成交,就打平
代理$3,8252.11代理多带来 111% 的成交,才打平

这张表把“渠道越省力、净得越低”翻译成了一个可执行的判断线。代理如果能带来两倍以上的成交,总净得可以超过直销;如果只能带来一倍半,直销更划算。平台和经销的门槛低一些,但它们的控制权也更少。

这里有一个容易漏掉的前提:直销的销售动作不是免费的。LedgerLite 的 CAC 是 140 美元,按 8,500 美元的项目换算,直销净得会从 8,075 降到 7,935,代理的匹配倍数从 2.11 降到 2.07。CAC 越高,直销的净得优势越小,渠道的销量倍数门槛越低。渠道比较要把获客成本放进直销一侧,而不是把直销当成零成本。

案例:Nord 的 55%、Tidecast 的 30%、LedgerLite 的 84.2%

Nord 的主渠道是转介绍,分成比例 55%。一笔 8,500 美元的项目,Nord 净得 3,825 美元。Nord 的前 3 家客户占收入 48%,这意味着转介绍不只是获客方式,也是收入集中度的一部分。把 55% 套到 20 笔转介绍项目上,Nord 年净得 76,500 美元;同样 20 笔如果走直销,净得 161,500 美元。反过来,10 笔直销的净得是 80,750 美元,已经超过 20 笔转介绍。要匹配 10 笔直销,Nord 需要 21.1 笔转介绍,取整是 22 笔。

Nord 的场景笔数单笔净得年净得
转介绍 55%20$3,825$76,500
转介绍 55%22$3,825$84,150
直销 95%10$8,075$80,750
直销 95%20$8,075$161,500

Nord 的毛利率是 84.4%,但这是扣除外包和工具直接成本之后的毛利,不是扣除 55% 转介绍佣金之后的净利。如果把 55% 套到全年收入 154,320 美元上,渠道成本是 84,876 美元,相当于毛利 130,320 美元的 65.1%。这也是为什么案例把转介绍列为关键依赖:它不是一笔普通的获客费用,而是会吞掉大部分毛利的收入分成。

Tidecast 的主渠道是 Steam,销量占比 80%,平台分成 30%。Steam 渠道在扣掉 4% 退款后,净得率是 67.2%;官网渠道扣掉 5% 支付费后是 91.2%;按 80/20 加权,整体净得率是 72.0%,对应净得 138,171 美元。平台分成 30% 只是第一层,退款是第二层,销量占比是第三层。三层叠在一起,才是 Tidecast 的真实净得率。

Steam 销量占比混合净得率8,500 美元净得
50%79.2%$6,732
80%72.0%$6,120
90%69.6%$5,916

这张表说明,平台依赖不需要改变分成比例,只要销量结构变化,净得就会变。Steam 占比从 80% 升到 90%,同样一笔 8,500 美元的标价收入,净得从 6,120 降到 5,916,少了 204 美元。平台分成是合同条款,销量结构是经营结果,两者一起决定渠道的真实成本。

LedgerLite 是直销,毛利率 84.2%。这个数字常被误读成“直销净得 84.2%”,其实它已经扣掉了云 18,000 美元、支付 12,000 美元和支持 8,000 美元。支付费一项占收入 5.0%,和本节直销渠道的 5% 抽成对齐;云和支持是交付成本,不在渠道抽成里。LedgerLite 的直销优势来自 260 家客户、CAC 140 美元和 LTV/CAC 30.9,而不是来自“没有渠道费”这一句话。

案例主渠道渠道抽成8,500 美元净得关键依赖
Nord Studio转介绍55%$3,825前 3 家客户 48%
TidecastSteam 80% + 官网 20%30% / 5%$6,120(混合净得)Steam 销量 80%
LedgerLite直销5% 支付费$8,075前 5 家客户 31%

三个案例放在一起,渠道选择的顺序就清楚了:LedgerLite 用直销换来了最高的单笔净得,但承担了完整的获客和交付;Tidecast 用平台换来了销量,但让出了 30% 和一部分定价权;Nord 用转介绍换来了成交,但让出了 55% 和客户关系。三种选择都能成立,前提是厂商知道自己用净得换了什么。

把渠道选择写成代码

下面的 channel.ts 把四种渠道的抽成、净得和可控性固化成可复算的函数。channelTerms 返回每种渠道的条款,channelNet 算单笔净得,compareChannels 按固定顺序比较四种渠道,rankChannels 按净得排序,netRatioBps 算两个渠道的净得比例。

// file: src/contract/channel.ts
// tier: L1
// verify: node --test test/contract/channel.test.ts

import { type Cents } from "../core/money.ts";
import { type Bps, applyRate, divide } from "../core/rate.ts";
import { type Result, fail, ok } from "../core/result.ts";

export type ChannelKind = "direct" | "agent" | "distributor" | "platform";

export type ChannelTerms = {
  kind: ChannelKind;
  takeRateBps: Bps;
  netRateBps: Bps;
  control: "high" | "medium" | "low" | "minimal";
  effort: "high" | "medium" | "low" | "minimal";
  ownsCustomer: boolean;
  controlsPrice: boolean;
};

/** Teaching assumption: each channel takes a fixed share of list revenue. */
export const CHANNEL_TAKE_BPS: Record<ChannelKind, Bps> = {
  direct: 500,
  platform: 3000,
  distributor: 4000,
  agent: 5500,
};

const TERMS: Record<ChannelKind, ChannelTerms> = {
  direct: {
    kind: "direct",
    takeRateBps: CHANNEL_TAKE_BPS.direct,
    netRateBps: 10000 - CHANNEL_TAKE_BPS.direct,
    control: "high",
    effort: "high",
    ownsCustomer: true,
    controlsPrice: true,
  },
  platform: {
    kind: "platform",
    takeRateBps: CHANNEL_TAKE_BPS.platform,
    netRateBps: 10000 - CHANNEL_TAKE_BPS.platform,
    control: "medium",
    effort: "medium",
    ownsCustomer: false,
    controlsPrice: false,
  },
  distributor: {
    kind: "distributor",
    takeRateBps: CHANNEL_TAKE_BPS.distributor,
    netRateBps: 10000 - CHANNEL_TAKE_BPS.distributor,
    control: "low",
    effort: "low",
    ownsCustomer: false,
    controlsPrice: false,
  },
  agent: {
    kind: "agent",
    takeRateBps: CHANNEL_TAKE_BPS.agent,
    netRateBps: 10000 - CHANNEL_TAKE_BPS.agent,
    control: "minimal",
    effort: "minimal",
    ownsCustomer: false,
    controlsPrice: false,
  },
};

export type ChannelOutcome = {
  kind: ChannelKind;
  grossCents: Cents;
  takeCents: Cents;
  netCents: Cents;
  netRateBps: Bps;
  terms: ChannelTerms;
};

export function channelTerms(kind: ChannelKind): Result<ChannelTerms> {
  const terms = TERMS[kind];
  if (!terms) {
    return fail(`unknown channel kind: ${kind}`);
  }
  return ok({ ...terms });
}

export function channelNet(
  grossCents: Cents,
  kind: ChannelKind,
): Result<ChannelOutcome> {
  if (!Number.isInteger(grossCents) || grossCents <= 0) {
    return fail("gross revenue must be a positive integer amount in cents");
  }
  const terms = channelTerms(kind);
  if (!terms.ok) {
    return terms;
  }
  const takeCents = applyRate(grossCents, terms.value.takeRateBps);
  return ok({
    kind,
    grossCents,
    takeCents,
    netCents: grossCents - takeCents,
    netRateBps: terms.value.netRateBps,
    terms: terms.value,
  });
}

const ORDER: ChannelKind[] = ["direct", "platform", "distributor", "agent"];

export function compareChannels(grossCents: Cents): Result<ChannelOutcome[]> {
  const outcomes: ChannelOutcome[] = [];
  for (const kind of ORDER) {
    const outcome = channelNet(grossCents, kind);
    if (!outcome.ok) {
      return outcome;
    }
    outcomes.push(outcome.value);
  }
  return ok(outcomes);
}

/** Highest net first. Ties keep the fixed direct-to-agent order. */
export function rankChannels(grossCents: Cents): Result<ChannelOutcome[]> {
  const compared = compareChannels(grossCents);
  if (!compared.ok) {
    return compared;
  }
  const ranked = [...compared.value].sort((a, b) => {
    if (b.netCents !== a.netCents) {
      return b.netCents - a.netCents;
    }
    return ORDER.indexOf(a.kind) - ORDER.indexOf(b.kind);
  });
  return ok(ranked);
}

/**
 * How much one dollar of the first channel's net is worth relative to the
 * second. A value below 10000 bps means the first channel keeps less.
 */
export function netRatioBps(
  grossCents: Cents,
  first: ChannelKind,
  second: ChannelKind,
): Result<Bps> {
  const a = channelNet(grossCents, first);
  if (!a.ok) {
    return a;
  }
  const b = channelNet(grossCents, second);
  if (!b.ok) {
    return b;
  }
  if (b.value.netCents === 0) {
    return fail("the second channel has no net revenue to compare against");
  }
  return ok(divide(a.value.netCents, b.value.netCents));
}

把 8,500 美元代入,channelNet 返回直销 807,500 美分、平台 595,000 美分、经销 510,000 美分、代理 382,500 美分,即 8,075、5,950、5,100、3,825 美元。netRatioBps(850_000, "direct", "agent") 返回 21,111 基点,即 211.1%,对应“一笔直销顶 2.11 笔代理”。

代码里有三个刻意的限制。第一,抽成比例是固定值,不随销量、品类或区域变化;真实合同里的阶梯返点和区域保护,会在 9.2 节单独处理。第二,净得只扣渠道抽成,不扣交付成本、退款和税费;它回答的是“渠道拿走多少”,不是“这门生意最后赚多少”。第三,可控性用 high、medium、low、minimal 四档表示,是定性判断,不是可以加总的分数。

渠道选择还有一个代码没有覆盖的维度:时间。代理可能第一个月就带来成交,直销可能要六个月才跑通获客;平台可能上线就有流量,经销可能要先培训三个月。净得是静态的,现金流是动态的。把渠道切换的时间成本放进模型,是 9.3 节的内容。

小结

  • 四种渠道的差别不只是抽成比例,还包括谁收钱、谁承担销售动作、谁拥有客户和定价权。
  • 同一笔 8,500 美元的项目,直销净得 8,075 美元、平台 5,950 美元、经销 5,100 美元、代理 3,825 美元。
  • 排序是直销、平台、经销、代理:渠道越省力,净得越低,控制越弱。
  • 要匹配一笔直销,平台需要 1.36 笔、经销需要 1.58 笔、代理需要 2.11 笔;这是渠道的销量门槛。
  • Nord 的 20 笔转介绍净得 76,500 美元,仍低于 10 笔直销的 80,750 美元;要匹配 10 笔直销,需要 22 笔转介绍。
  • Tidecast 的 80% Steam 依赖把整体净得率压到 72.0%;Steam 占比升到 90%,净得率降到 69.6%。
  • LedgerLite 的 84.2% 是扣除云、支付和支持之后的毛利,不是渠道抽成前的净得;两者不是同一层。
  • 直销的获客成本要放进比较:CAC 140 美元会把代理的匹配倍数从 2.11 降到 2.07。

阅读导航:上一节:8.3 授权审计与终止 · 下一节:9.2 返点、区域保护与价格冲突 。

常见错误与边界

  1. 把渠道抽成当成唯一成本。 直销还有获客、交付和支持成本;平台还有退款、促销和合规成本;代理还有客户关系流失。只比抽成,会把最便宜的渠道误判成最赚钱的渠道。
  2. 用同一笔收入比较不同销量。 渠道的价值不只是单笔净得,还包括它能带来多少笔。代理的净得低,但如果它能带来两倍以上的成交,总净得可能更高;反过来,直销的净得高,但如果没有获客能力,高净得只是账面数字。
  3. 把毛利率当成渠道净得。 LedgerLite 的 84.2% 已经扣掉云、支付和支持,不是渠道抽成前的 95%。两个数字放在一张表里比较,会高估直销的优势。
  4. 忽略销量结构对净得率的影响。 Tidecast 的 72.0% 是 80% Steam 和 20% 官网的加权结果;Steam 占比升到 90%,净得率降到 69.6%。分成比例没变,净得变了。
  5. 把 55% 转介绍当成普通获客成本。 55% 是收入分成,不是一次性的广告费;套到全年收入上,它会吞掉大部分毛利,并改变收入集中度。
  6. 只看单笔净得,不看客户归属。 代理和经销拿走的不只是钱,还有客户名单、复购关系和定价对话;这些在第 2 年、第 3 年会变成更高的获客成本。
  7. 把平台当成纯渠道。 平台同时是渠道、规则制定者和部分售后责任方;平台分成之外,还有退款、促销、封禁和排名规则,都会改变净得。
  8. 用固定抽成比例套所有合同。 真实合同里的返点、区域保护和最低售价会改变实际单价;固定比例只能回答第一层问题,不能替代合同条款分析。
  9. 忽略渠道的时间成本。 代理可能马上带来成交,直销要几个月才能跑通;只比年化净得,会低估转型期的现金缺口。
  10. 把渠道选择当成一次性决定。 渠道会随着产品、客单价和市场变化而失效;今天划算的代理,明天可能因为价格冲突而退出,退出成本要提前算。

本节的边界是“同一笔收入、同一时点、四种固定抽成”的静态比较。它假设四种渠道都能完成同样的交付,不含销量差异、退款、税费、获客成本和渠道切换时间。它足够回答“同一笔钱走不同渠道我留多少”,但不足以回答“换渠道要多久、要花多少”。后者需要把过渡期、未结佣金和客户归属放进模型,见 9.3 渠道合同与退出 。渠道集中度对估值的影响,见 7.2 客户集中度 。本节不构成法律意见,具体渠道条款请由律师审阅。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《移动游戏产品的架构·商业化与发行工程》附录 C 商业化与发行评审清单
  2. 《移动游戏产品的架构·商业化与发行工程》附录 B 双案例商业化事实表
  3. 《移动游戏产品的架构·商业化与发行工程》附录 A 商业化与发行术语速查