Custom code
Custom Code is code you write by hand in the Staging Repository alongside Soxom’s generator output. It lives on extended/* branches and survives regeneration, so you can ship helpers, convenience methods, and bespoke logic without losing them on the next build.
When to use it
Section titled “When to use it”- Convenience methods Soxom can’t infer from the spec (composite operations, chained calls)
- Custom serializers or type aliases that depend on internal context
- Helper utilities — retries with domain-specific semantics, pagination wrappers, etc.
- Extra types or interfaces the OpenAPI spec doesn’t describe
If the behavior can be expressed in OpenAPI (via vendor extensions like x-soxom-pagination, x-soxom-retries), prefer that — generator output stays canonical and the line count stays low.
How it works
Section titled “How it works”The Staging Repository has two parallel branch families:
codegen/*— generator output, rewritten on every buildextended/*— your hand-written code merged on top of the matchingcodegen/*
A build runs the generator on a codegen/<branch> and replays your extensions onto an extended/<branch>. Anything in the extension directory for the language is left alone; anything outside is regenerated from scratch.
Adding custom code
Section titled “Adding custom code”-
Clone the project’s Staging Repository.
-
Check out
extended/nextfor the next build, orextended/<branch>for a preview branch. -
Add files in the language-specific extension location:
Language Path TypeScript src/extended/Python <package>/extended/Java src/main/java/.../extended/ -
Open a pull request against
extended/next. CI runs the SDK’s test suite and lints; Soxom merges intonextonce checks pass.
What gets preserved
Section titled “What gets preserved”Anything inside the extension directory survives regeneration. Modifications to generator-managed files (everything outside the extension directory) are overwritten on the next build.
Example
Section titled “Example”A small TypeScript helper that wraps two generated calls:
import { Client } from "../client";import type { User, Role } from "../models";
export async function listUsersWithRoles( client: Client,): Promise<Array<User & { roles: Role[] }>> { const users = await client.users.list(); return Promise.all( users.map(async (user) => ({ ...user, roles: await client.users.listRoles(user.id), })), );}The 20 lines above count against your Custom Code budget for that target.
Limits
Section titled “Limits”Custom Code is plan-gated, per target:
| Plan | Lines per target |
|---|---|
| Professional | 1,000 |
| Business | 10,000 |
| Enterprise | Unlimited |
The count is the diff between extended/next and the latest codegen/next — anything you added (in any file) counts. Keep extensions confined to the extension directory so the number stays predictable; edits to generator-managed files inflate the count and get overwritten on the next build anyway.
See Usage limits for what happens when you exceed the cap and how to recover.