diff --git a/server/src/__tests__/openapi-routes.test.ts b/server/src/__tests__/openapi-routes.test.ts index e70b913ba2d..3500aa68f94 100644 --- a/server/src/__tests__/openapi-routes.test.ts +++ b/server/src/__tests__/openapi-routes.test.ts @@ -340,6 +340,16 @@ describe("openapi routes", () => { expect(operation.description).toMatch(/include\.projects/); } }); + it("documents the safe company import body so agents can preview and resolve agent name conflicts", () => { + const spec = buildOpenApiSpec(); + for (const path of ["/api/companies/{companyId}/imports/preview", "/api/companies/{companyId}/imports/apply"]) { + const operation = spec.paths[path].post; + const body = operation.requestBody.content["application/json"].schema; + expect(body.required).toEqual(expect.arrayContaining(["source", "target"])); + expect(body.properties).toMatchObject({ collisionStrategy: expect.anything(), nameOverrides: expect.anything(), include: expect.anything() }); + expect(operation.description).toMatch(/replace/); + } + }); it("documents generic webhook provenance headers and accepted responses without a provider-specific endpoint", () => { const spec = buildOpenApiSpec(); const operation = spec.paths["/api/routine-triggers/public/{publicId}/fire"].post; diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index 82c03636034..548232c49ff 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -2213,7 +2213,11 @@ registry.registerPath({ path: "/api/companies/{companyId}/imports/preview", tags: ["companies"], summary: "Preview company import", - request: { params: z.object({ companyId: z.string() }) }, + description: "Safe import into this company only: target must be { mode: \"existing_company\", companyId } for the route company or a new company, and collisionStrategy may be \"rename\" or \"skip\" (\"replace\" is rejected, so an existing agent is never overwritten). nameOverrides maps an incoming agent, project or issue slug to the name it should get. Preview never changes the company; apply creates or reuses resources and returns them.", + request: { + params: z.object({ companyId: z.string() }), + body: jsonBody(companyPortabilityPreviewSchema), + }, responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized }, }); @@ -2222,7 +2226,11 @@ registry.registerPath({ path: "/api/companies/{companyId}/imports/apply", tags: ["companies"], summary: "Apply company import", - request: { params: z.object({ companyId: z.string() }) }, + description: "Safe import into this company only: target must be { mode: \"existing_company\", companyId } for the route company or a new company, and collisionStrategy may be \"rename\" or \"skip\" (\"replace\" is rejected, so an existing agent is never overwritten). nameOverrides maps an incoming agent, project or issue slug to the name it should get. Preview never changes the company; apply creates or reuses resources and returns them.", + request: { + params: z.object({ companyId: z.string() }), + body: jsonBody(companyPortabilityImportSchema), + }, responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized }, });