Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cli-e2e.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ async function mockFetch(input, init) {
if (path.match(/^\/projects\/v1\/[^/]+$/) && method === "DELETE") {
return Promise.resolve(noContent());
}
if (path.match(/^\/billing-accounts\/v1\/admin\/[^/]+\/lease-perpetual$/) && method === "POST") {
if (path.match(/^\/billing\/v1\/admin\/accounts\/[^/]+\/lease-perpetual$/) && method === "POST") {
const accountId = path.split("/").at(-2);
const desired = Boolean(body?.lease_perpetual);
return Promise.resolve(json({
Expand Down Expand Up @@ -1880,7 +1880,7 @@ describe("CLI e2e happy path", () => {
const prevFetch = globalThis.fetch;
globalThis.fetch = (input, init) => {
const url = typeof input === "string" ? input : (input instanceof Request ? input.url : String(input));
if (url.includes("/billing-accounts/v1/admin/ba_external/lease-perpetual")) {
if (url.includes("/billing/v1/admin/accounts/ba_external/lease-perpetual")) {
seenUrl = url;
if (input instanceof Request) {
seenMethod = input.method;
Expand All @@ -1905,7 +1905,7 @@ describe("CLI e2e happy path", () => {
globalThis.fetch = prevFetch;
}
assert.ok(
seenUrl && seenUrl.includes("/billing-accounts/v1/admin/ba_external/lease-perpetual"),
seenUrl && seenUrl.includes("/billing/v1/admin/accounts/ba_external/lease-perpetual"),
`lease-perpetual should hit the admin endpoint; got: ${seenUrl}`,
);
assert.equal(seenMethod, "POST");
Expand Down
6 changes: 3 additions & 3 deletions sdk/src/namespaces/admin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ describe("admin.getProjectFinance", () => {
});

describe("admin.setLeasePerpetual (v1.57)", () => {
it("POSTs to /billing-accounts/v1/admin/:id/lease-perpetual with admin headers", async () => {
it("POSTs to /billing/v1/admin/accounts/:account_id/lease-perpetual with admin headers", async () => {
const { fetch, calls } = mockFetch(() =>
json({
status: "ok",
Expand All @@ -226,7 +226,7 @@ describe("admin.setLeasePerpetual (v1.57)", () => {
assert.equal(calls[0]!.method, "POST");
assert.equal(
calls[0]!.url,
"https://api.test/billing-accounts/v1/admin/ba_known/lease-perpetual",
"https://api.test/billing/v1/admin/accounts/ba_known/lease-perpetual",
);
assert.equal(calls[0]!.headers["X-Admin-Mode"], "1");
assert.equal(calls[0]!.headers["SIGN-IN-WITH-X"], "t");
Expand All @@ -253,7 +253,7 @@ describe("admin.setLeasePerpetual (v1.57)", () => {
await sdk(fetch).admin.setLeasePerpetual("ba/has space", true);
assert.equal(
calls[0]!.url,
"https://api.test/billing-accounts/v1/admin/ba%2Fhas%20space/lease-perpetual",
"https://api.test/billing/v1/admin/accounts/ba%2Fhas%20space/lease-perpetual",
);
});
});
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/namespaces/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,14 @@ export class Admin {
* `reactivated: true`.
*
* Platform-admin only. Calls
* `POST /billing-accounts/v1/admin/:id/lease-perpetual`.
* `POST /billing/v1/admin/accounts/:account_id/lease-perpetual`.
*/
async setLeasePerpetual(
billingAccountId: string,
perpetual: boolean,
): Promise<SetLeasePerpetualResult> {
return this.client.request<SetLeasePerpetualResult>(
`/billing-accounts/v1/admin/${encodeURIComponent(billingAccountId)}/lease-perpetual`,
`/billing/v1/admin/accounts/${encodeURIComponent(billingAccountId)}/lease-perpetual`,
{
method: "POST",
headers: { "X-Admin-Mode": "1" },
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ server.tool(

server.tool(
"admin_set_lease_perpetual",
"Toggle a billing account's `lease_perpetual` escape hatch (v1.57+). When `lease_perpetual: true`, the account never advances past `active` regardless of lease expiry; every project on the account inherits the pinned state. Enabling on a grace-state account (past_due / frozen / dormant) reactivates inline and returns `reactivated: true`. Platform-admin only — uses the configured allowance wallet for admin auth. Replaces the v1.56 `pin_project` (gateway endpoint /projects/v1/admin/:id/pin was removed in v1.57). Calls POST /billing-accounts/v1/admin/:id/lease-perpetual.",
"Toggle a billing account's `lease_perpetual` escape hatch (v1.57+). When `lease_perpetual: true`, the account never advances past `active` regardless of lease expiry; every project on the account inherits the pinned state. Enabling on a grace-state account (past_due / frozen / dormant) reactivates inline and returns `reactivated: true`. Platform-admin only — uses the configured allowance wallet for admin auth. Replaces the v1.56 `pin_project` (gateway endpoint /projects/v1/admin/:id/pin was removed in v1.57). Calls POST /billing/v1/admin/accounts/:account_id/lease-perpetual.",
adminSetLeasePerpetualSchema,
async (args) => handleAdminSetLeasePerpetual(args),
);
Expand Down
2 changes: 1 addition & 1 deletion sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ const SURFACE: Capability[] = [
// v1.57: pin/unpin endpoints removed. Per-project pin is superseded by the
// account-level escape hatch (admin_set_lease_perpetual). archive and
// reactivate are operator moderation actions, scoped to a single project.
{ id: "admin_set_lease_perpetual", endpoint: "POST /billing-accounts/v1/admin/:id/lease-perpetual", mcp: "admin_set_lease_perpetual", cli: "admin:lease-perpetual", openclaw: "admin:lease-perpetual" },
{ id: "admin_set_lease_perpetual", endpoint: "POST /billing/v1/admin/accounts/:account_id/lease-perpetual", mcp: "admin_set_lease_perpetual", cli: "admin:lease-perpetual", openclaw: "admin:lease-perpetual" },
{ id: "admin_archive_project", endpoint: "POST /projects/v1/admin/:id/archive", mcp: "admin_archive_project", cli: "admin:archive", openclaw: "admin:archive" },
{ id: "admin_reactivate_project", endpoint: "POST /projects/v1/admin/:id/reactivate", mcp: "admin_reactivate_project", cli: "admin:reactivate", openclaw: "admin:reactivate" },
{ id: "promote_user", endpoint: "POST /projects/v1/admin/:id/promote-user", mcp: "promote_user", cli: "projects:promote-user", openclaw: "projects:promote-user" },
Expand Down
Loading