SK Franchise · Developers

A platform API, not a closed app.

Other SoftKnack products and verticals build on SK Franchise. It is versioned at /v1, publishes an OpenAPI contract generated from its own code, accepts service tokens, and emits domain events other products can subscribe to.

01

How it fits together

Identity comes from SoftKnack sign-in — SK Franchise has no login of its own. Invoices are raised in SK Billing, events go out through an outbox after each change commits, and every table is isolated per organisation in the database.

fig · the shape of itSoftKnack sign-insession · rolesSK Franchise API/v1 · row-level tenancyoutbox written in the same transactionSK Billing · invoicesdomain eventsHQ metrics
02

Your first call in three steps

Sign in, read the network, then make a change with an idempotency key.

1

Authenticate

Use the SoftKnack session cookie, or a bearer token — a user token, or a service token delegated through the platform backbone.

2

Read the network

GET /v1/network/units lists the outlets your role may see. A franchisee only ever sees their own.

3

Write with a key

Every POST and PATCH needs an Idempotency-Key. Without one the API refuses the write; with the same key it returns the first result.

Terminal
curl -X POST https://franchise.dev.api.softknack.com/v1/settlements/runs \
  -H "Authorization: Bearer <platform token>" \
  -H "Idempotency-Key: 9f2c-4d1a-...-e7b3" \
  -H "Content-Type: application/json" \
  -d '{ "period": "2026-09" }'

Illustrative — the exact request and response shapes are in the published OpenAPI contract.

03

Events other products can build on

Events are written to an outbox in the same transaction as the change, and sent after it commits — so an event is never sent for a change that rolled back, and never lost for one that didn't. Failed deliveries show up in /v1/outbox and can be retried.

EventWhen it fires
franchise.unit.createdA new outlet is added to the network.
franchise.unit.status_changedAn outlet moves stage or status.
franchise.unit.went_liveOnboarding is complete and the outlet is open.
franchise.settlement.approvedA settlement has all the approvals it needs.
franchise.settlement.postedThe settlement is invoiced in SK Billing.
franchise.payment.recordedA payment is recorded against a settlement.
franchise.fund.request_decidedA Marketing Fund request is approved or rejected.
franchise.agreement.renewal_dueAn agreement is nearing its renewal date.
04

Guarantees, not vibes

The rules are enforced in the database, not just in the code that calls it.

Idempotent writes

Every POST and PATCH takes an Idempotency-Key. A retried request returns the original result instead of doing the work twice.

Row-level tenancy

Every table is isolated per organisation with forced row-level security. One org can never read another's outlets.

Money as strings

Amounts are decimal strings with their currency, never floating-point numbers. The client never computes money.

Frozen history

Royalty rules used by a settlement, and posted settlements themselves, can't be changed — database triggers refuse it.

Two-person rules

Approval quorums and document confirmations are constraints, so a second click by the same person is refused.

Contract from the code

The OpenAPI contract is generated from the API's own validators, so the documentation matches what the API accepts.

The docs go deeper.

Every endpoint, schema and error, from the published contract.

docs.softknack.com/franchise  See pricing →