RSL licensing

RSL 1.0 (Really Simple Licensing, rslstandard.org) is the open XML standard for machine-readable content licensing. The SDK renders your live policy as an RSL document, so the license you publish is the policy you actually enforce.

Generate the document

ts
import { createRslDocument } from "@corri/sdk/server";

const xml = createRslDocument(policyDefinition, {
  contentUrl: "https://your-site.example/api/protected-report", // default "/"
  paymentUrl: "https://your-site.example/docs/payments",        // where to acquire a license
  // licenseServer: "https://…",        // OLP license server endpoint, if any
  // standardLicenseUrl: "https://…"    // e.g. a Creative Commons URL
});

The policy-to-RSL mapping:

Policy constructRSL output
deny rules on purposes<prohibits type="usage">
allow rules on purposes<permits type="usage">
charge rules<payment type="use"> with <amount> and the acquisition URL
Attribution obligations<payment type="attribution">
Obligations without an RSL token (e.g. prohibit-republication)Carried as XML comments for human review

Serve it

Serve the XML with content type application/rsl+xml (exported as RSL_MEDIA_TYPE). This site does exactly that at /license.xml, generated from the live demo policy:

app/license.xml/route.tsts
import { createRslDocument } from "@corri/sdk/server";
import { DEMO_POLICY } from "@/lib/demo-world";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

export async function GET(request: Request) {
  const origin = new URL(request.url).origin;
  const xml = createRslDocument(DEMO_POLICY, {
    contentUrl: `${origin}/api/protected-report`,
    paymentUrl: `${origin}/docs/payments`
  });
  return new Response(xml, {
    headers: { "content-type": "application/rsl+xml; charset=utf-8" }
  });
}

Advertise it

Pass rsl: { policyUrl } to createAgentAccess and protected responses advertise the license document, so agents can discover your terms before (or while) requesting content. The header helper is also exported directly:

ts
import { rslHeaders } from "@corri/sdk";
rslHeaders("https://your-site.example/license.xml");
// → headers advertising the RSL license document (Link rel="license")

Parsing (agent side)

Agents can read a publisher's terms with the safe parser, DOCTYPE declarations are rejected and entities are never resolved, so XXE is structurally impossible:

ts
import { parseRslDocument } from "@corri/sdk";

const doc = parseRslDocument(xml);
// doc.contents[0] → {
//   url, server?,
//   licenses: [{ permits, prohibits, payments }]
// }

Purpose mapping

SDK purposes and RSL usage tokens interconvert via two exported maps: PURPOSE_TO_RSL_USAGE (e.g. training train-ai) and RSL_USAGE_TO_PURPOSES for the reverse direction.

One source of truth: because the document is generated from the same PolicyDefinition the server enforces, your published license can't drift from your actual access behavior.