mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 04:43:58 +00:00
OpenAffiliate 0.1: one file a merchant serves about the commission it pays (#166)
The descriptor at /.well-known/openaffiliate.json (programs with pays, link, window, attribution, hold_days, payout, approval, self), the four calls (join with an OpenProfile.md, link with ?oa=code, read the ledger, get paid to your own address), webhooks, discovery, what a directory owes a merchant, and what is deliberately absent: no network in the money, no tracking host, no application form, no exclusivity, no impression payments. Landing page at /openaffiliate, registered in DOC_SLUGS, NAV, sitemap and llms.txt. Reference implementation is crawlproof.com/affiliate. Claude-Session: https://claude.ai/code/session_01CDEiDss9RWYibtmxSk5Gr2 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
8269c12b75
commit
938bd5f632
6 changed files with 507 additions and 0 deletions
|
|
@ -32,6 +32,7 @@ export function GET(): Response {
|
|||
- [OpenDisk](${SITE_URL}/opendisk): One file a machine serves about the disk it will rent: free GiB, price per GiB-month, location, policy, proof cadence and hub standing, discovered at /.well-known/opendisk.json. What a peer-to-peer storage market is made of; reference marketplace d1sks.com.
|
||||
- [OpenCoupon](${SITE_URL}/opencoupon): One file a merchant serves about what is on offer right now, at /.well-known/opencoupon.json: every code, sale and shipping threshold with kind, value, scope, dates, status and regions, expired codes kept so directories learn they died. A coupon site reads the merchant instead of a forum thread.
|
||||
- [OpenRecipe.md](${SITE_URL}/openrecipe): One Markdown file that is a recipe: summary block (Serves, Prep, Cook, Cuisine, Diet, Author, Source), ingredients and steps as written, notes, nutrition; served next to the page or linked with rel="openrecipe"; schema.org/Recipe JSON-LD is derived from it, never the reverse.
|
||||
- [OpenAffiliate](${SITE_URL}/openaffiliate): One file a merchant serves about the commission it pays, at /.well-known/openaffiliate.json: programs with what pays (sale, subscription, signup, lead, install), percent or amount, attribution window, hold days and payout methods; four calls let a person or an agent join with an OpenProfile.md, link with ?oa=code, read its own ledger and get paid to its own address. No network in the money; reference implementation crawlproof.com/affiliate.
|
||||
- [AgentSwarm](${SITE_URL}/agent-swarm): Provider-neutral agent orchestration, model routing, and cost controls.
|
||||
- [AgentByte](${SITE_URL}/agentbyte): Agent screening sessions, policy events, and APIs.
|
||||
- [Credential Sharing](${SITE_URL}/credential-sharing): End-to-end-encrypted team vaults, plus source/target credential diffs, approval, sync, rollback, and audit.
|
||||
|
|
|
|||
233
apps/logicsrc-web/src/app/openaffiliate/page.tsx
Normal file
233
apps/logicsrc-web/src/app/openaffiliate/page.tsx
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { SiteShell } from "@/components/site-shell";
|
||||
import { mono, pre, table, td, th } from "../openontology/ui";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "OpenAffiliate · LogicSRC",
|
||||
description:
|
||||
"OpenAffiliate is one file a merchant serves about the commission it pays, at /.well-known/openaffiliate.json, and four calls that let a person or an agent earn it: join with a profile, link with one parameter, read your own ledger, get paid to your own address. No network in the money.",
|
||||
alternates: { canonical: "/openaffiliate" }
|
||||
};
|
||||
|
||||
const DESCRIPTOR = `{
|
||||
"merchant": { "name": "CrawlProof", "web": "https://crawlproof.com", "currency": "USD",
|
||||
"terms": "https://crawlproof.com/affiliate/terms" },
|
||||
"updated": "2026-09-13T06:00:00Z",
|
||||
"programs": [
|
||||
{ "id": "partners", "title": "CrawlProof partner program",
|
||||
"join": "https://crawlproof.com/api/affiliate/v1/join",
|
||||
"ledger": "https://crawlproof.com/api/affiliate/v1/ledger",
|
||||
"approval": "open",
|
||||
"pays": [
|
||||
{ "event": "sale", "kind": "percent", "value": 30 },
|
||||
{ "event": "subscription", "kind": "percent", "value": 30, "months": 12 },
|
||||
{ "event": "signup", "kind": "amount", "value": 0.5 }
|
||||
],
|
||||
"link": { "param": "oa", "deep": true },
|
||||
"window": 30, "attribution": "last", "hold_days": 30,
|
||||
"payout": { "methods": ["usdc/eip155:137"], "min": 10, "schedule": "weekly" },
|
||||
"self": "refused", "status": "active" }
|
||||
]
|
||||
}`;
|
||||
|
||||
const JOIN = `POST https://crawlproof.com/api/affiliate/v1/join
|
||||
{ "profile": "https://anthony.example/.well-known/openprofile.md" }
|
||||
|
||||
201 { "membership": "am_8f3c", "status": "active", "code": "anthony",
|
||||
"link": "https://crawlproof.com/?oa=anthony", "token": "oa_5Kq…",
|
||||
"ledger": "https://crawlproof.com/api/affiliate/v1/ledger" }`;
|
||||
|
||||
const EVENTS: Array<[string, string, string]> = [
|
||||
["sale", "a one-time charge", "percent of amount, or a flat amount"],
|
||||
["subscription", "each charge of a recurring one", "months caps how many renewals pay; absent is every one"],
|
||||
["signup", "an account created", "usually a flat amount"],
|
||||
["lead", "a form submitted", "a flat amount"],
|
||||
["install", "an app installed", "a flat amount"],
|
||||
["other", "the merchant's own words", "kept, listed, not filtered on"]
|
||||
];
|
||||
|
||||
const CALLS: Array<[string, string]> = [
|
||||
["Join", "POST the program's join URL with an OpenProfile.md URL. Back comes a code, a link, a token and the terms as they stood. open answers active at once; review answers pending."],
|
||||
["Link", "The merchant's URL with ?oa=code. No redirect host, no shortener, no pixel. deep: true means it works on any page, so you link to the product you recommend."],
|
||||
["Ledger", "GET the ledger with the token: clicks, every conversion with its status and hold, balances pending, approved and paid, every payout with its tx. A reversal must carry a reason."],
|
||||
["Payout", "The whole approved balance to your own pay address on the schedule, once it passes min. Nothing netted, because there is no network to pay."]
|
||||
];
|
||||
|
||||
const NETWORK: Array<[string, string]> = [
|
||||
["A third of the commission", "Nothing. The merchant pays the affiliate. A directory that charges does so as a stated fee, never as a share of a conversion."],
|
||||
["Apply, wait weeks", "A profile. approval: open answers at once; review says the merchant looks first, and says so in the file."],
|
||||
["Terms in a PDF you signed once", "Terms in a file at a fixed URL, fetched any time, kept with the membership as they stood at the join, changed forward only."],
|
||||
["A reversal with no reason", "A reversal without a reason is not a reversal. The affiliate reports it and a directory says so beside the program."],
|
||||
["Ten dashboards", "One ledger shape per program, readable by anyone with the token, so one page can show all of them."],
|
||||
["Sixty days, minus a fee, in their currency", "hold_days, then the schedule, to your own address, in the asset the file names. The tx is in the ledger."]
|
||||
];
|
||||
|
||||
const ABSENT: Array<[string, string]> = [
|
||||
["No network", "The merchant serves the terms, records the conversions and sends the money. Nobody sits in the middle of a payment."],
|
||||
["No tracking host", "A link is the merchant's URL with a parameter. Only a navigation sets attribution; an image, frame, script or prefetch sets nothing."],
|
||||
["No application form", "An affiliate is a profile. A person or an agent, with an operator who answers for the agent."],
|
||||
["No exclusivity", "A membership binds nobody to one program, and a program may not require it."],
|
||||
["No impression payments", "A view is not an event. The events are things a customer did."]
|
||||
];
|
||||
|
||||
export default function OpenAffiliatePage(): ReactNode {
|
||||
return (
|
||||
<SiteShell active="OpenAffiliate">
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<p className="eyebrow">LogicSRC standards surface</p>
|
||||
<h2>OpenAffiliate</h2>
|
||||
<p>
|
||||
One file a merchant serves about the commission it pays, and four calls that let a
|
||||
person or an agent earn it. No network in the money.
|
||||
</p>
|
||||
</div>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
Affiliate marketing runs through networks, and the networks are the problem. A merchant
|
||||
pays a third of every commission for a pixel and a payout file. An affiliate applies to
|
||||
each program by hand, waits weeks, and ends up with ten dashboards that disagree. Terms
|
||||
live in a PDF signed once. A conversion is reversed with no reason. A payout arrives sixty
|
||||
days later, minus a fee. And none of it is readable by a machine, so an agent that could
|
||||
earn by recommending the right product cannot find out what the commission is. The
|
||||
merchant already knows what it pays and what each sale was worth. OpenAffiliate is that,
|
||||
written down, at <code style={mono}>/.well-known/openaffiliate.json</code>.
|
||||
</p>
|
||||
<p style={{ color: "#5b6b7a" }}>
|
||||
Status: 0.1. The reference implementation is{" "}
|
||||
<a href="https://crawlproof.com/affiliate">crawlproof.com</a>, which runs its own
|
||||
program, joins other merchants' programs from the same dashboard, and pays in USDC on
|
||||
Polygon. The smallest valid file is a merchant with a name and a program with a title
|
||||
and one thing it pays.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>The descriptor</h2>
|
||||
<p>
|
||||
A commission fetched from the merchant's own origin is the commission the merchant
|
||||
says it pays, today, in words it cannot say it never agreed to.
|
||||
</p>
|
||||
</div>
|
||||
<pre style={pre}>{DESCRIPTOR}</pre>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
<code style={mono}>pays</code> is one entry per event. <code style={mono}>window</code>{" "}
|
||||
is the attribution window in days and <code style={mono}>attribution</code> whether a
|
||||
later click replaces an earlier one. <code style={mono}>hold_days</code> is the refund
|
||||
window a conversion waits out as pending. <code style={mono}>payout.methods</code> are{" "}
|
||||
<code style={mono}>asset/chain</code> pairs or a named rail. <code style={mono}>self</code>{" "}
|
||||
says whether the affiliate's own purchase pays. Unknown keys are kept.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Four calls</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<tbody>
|
||||
{CALLS.map(([what, how]) => (
|
||||
<tr key={what}>
|
||||
<td style={td}>
|
||||
<strong>{what}</strong>
|
||||
</td>
|
||||
<td style={td}>{how}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<pre style={pre}>{JOIN}</pre>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Six events</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={th}>event</th>
|
||||
<th style={th}>what happened</th>
|
||||
<th style={th}>how it pays</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{EVENTS.map(([event, what, how]) => (
|
||||
<tr key={event}>
|
||||
<td style={td}>
|
||||
<code style={mono}>{event}</code>
|
||||
</td>
|
||||
<td style={td}>{what}</td>
|
||||
<td style={td}>{how}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>What a network costs, and what replaces it</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={th}>on a network</th>
|
||||
<th style={th}>with OpenAffiliate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{NETWORK.map(([before, after]) => (
|
||||
<tr key={before}>
|
||||
<td style={td}>{before}</td>
|
||||
<td style={td}>{after}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>What is deliberately absent</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<tbody>
|
||||
{ABSENT.map(([what, why]) => (
|
||||
<tr key={what}>
|
||||
<td style={td}>
|
||||
<strong>{what}</strong>
|
||||
</td>
|
||||
<td style={td}>{why}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Where everything lives</h2>
|
||||
</div>
|
||||
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
|
||||
<li>
|
||||
<Link href="/docs/openaffiliate">Specification</Link>: the descriptor, eleven rules,
|
||||
six events, join, links and attribution, the ledger, webhooks, payouts, discovery,
|
||||
what a directory owes a merchant
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://crawlproof.com/affiliate">crawlproof.com/affiliate</a>: the reference
|
||||
implementation, running its own program and a directory of others
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/openprofile">OpenProfile.md</Link>, the affiliate's identity and pay
|
||||
address; <Link href="/opencoupon">OpenCoupon</Link>, a merchant's promotions in
|
||||
the same shape
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</SiteShell>
|
||||
);
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ const STATIC_ROUTES: Array<{
|
|||
{ path: "/opendisk", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/opencoupon", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openrecipe", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openaffiliate", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openontology/explore", changeFrequency: "daily", priority: 0.7 },
|
||||
{ path: "/openspec", changeFrequency: "weekly", priority: 0.8 },
|
||||
{ path: "/agent-swarm", changeFrequency: "weekly", priority: 0.8 },
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const NAV: Array<{ href: string; label: string; external?: boolean }> = [
|
|||
{ href: "/opendisk", label: "OpenDisk" },
|
||||
{ href: "/opencoupon", label: "OpenCoupon" },
|
||||
{ href: "/openrecipe", label: "OpenRecipe.md" },
|
||||
{ href: "/openaffiliate", label: "OpenAffiliate" },
|
||||
{ href: "/#cli", label: "CLI" },
|
||||
{ href: "/docs", label: "Docs" },
|
||||
{ href: "/blog", label: "Blog" },
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const DOC_SLUGS = [
|
|||
"opendisk",
|
||||
"opencoupon",
|
||||
"openrecipe",
|
||||
"openaffiliate",
|
||||
"openstream",
|
||||
"opencpu",
|
||||
"openmemory",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue