# How to Export and Import Company Configurations in Paperclip: Complete Guide

> Learn to export and import company configurations in Paperclip using REST APIs or CLI. Seamlessly transfer branding, agents, org charts, and more with this complete guide.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: how-to-guide
- Published: 2026-08-14

---

**Paperclip lets you move an entire company's configuration—branding, agents, org chart, projects, tasks, and skills—as a portable markdown-first package using REST APIs or the CLI.**

Exporting and importing company configurations in Paperclip enables portability across environments, version control of organizational data, and disaster recovery. The system treats company data as a **markdown-first package**: a zipped archive containing human-readable files plus a [`.paperclip.yaml`](https://github.com/paperclipai/paperclip/blob/main/.paperclip.yaml) side-car for runtime-specific metadata. This guide covers the full workflow using the Paperclip API and `paperclipai` CLI, with implementation details from the `paperclipai/paperclip` source code.

## Export Workflow: Creating a Portable Company Package

Paperclip exports follow a three-stage pattern: select components, preview the output, then generate the archive.

### Selecting Export Components

The `include` parameter controls which entities ship in the package. Valid flags are `company`, `agents`, `projects`, `issues`, and `skills`. The CLI defaults to `company` plus `agents`.

In [`server/src/routes/companies.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/companies.ts), the export endpoint validates requests using `companyPortabilityExportSchema`:

```typescript
router.post("/:companyId/export", async (req, res) => {
  const companyId = req.params.companyId as string;
  await assertSameCompanyCeoAgentOrBoard(req, companyId, "company exports");
  const body = companyPortabilityExportSchema.parse(req.body);
  const result = await portability.exportBundle(companyId, body);
  res.json(result);
});

```

*Source: [companies.ts – export endpoint](https://github.com/paperclipai/paperclip/blob/master/server/src/routes/companies.ts#L91-L96)*

Required permission: **CEO or Board member** of the source company.

### Previewing Before Export

Call `POST /api/companies/:companyId/exports/preview` or use `--dry-run` to see the exact file list and any environment-input prompts without creating a bundle.

### Running the Export

The export produces a `.zip` with this internal structure:

- [`COMPANY.md`](https://github.com/paperclipai/paperclip/blob/main/COMPANY.md) — company branding, settings, org chart
- `agents/` — agent definitions (one file per agent)
- `skills/` — skill configurations
- `projects/` — project definitions (if included)
- `tasks/` or `issues/` — task/issue data (if included)
- [`.paperclip.yaml`](https://github.com/paperclipai/paperclip/blob/main/.paperclip.yaml) — runtime metadata (adapter configs, budgets, secret references)

**CLI command:**

```bash
paperclipai company export 123e4567-89ab-cdef-0123-456789abcdef \
  --out ./my-company \
  --include company,agents,projects,issues,skills

```

## Import Workflow: Restoring or Migrating Company Data

Imports support two targets: **new company** (create) or **existing company** (update/merge).

### Import Targets and Collision Strategies

| Target | Endpoint | Use Case |
|--------|----------|----------|
| New company | `POST /api/companies/import` | Fresh migration, sandbox creation |
| Existing company | `POST /api/companies/:companyId/imports/apply` | Update agents, sync configurations |

Collision strategies (`rename`, `skip`, `replace`) determine behavior when entities already exist.

### Previewing the Import Plan

The preview endpoint parses and validates the package, returning a plan showing which entities will be **created**, **updated**, or **skipped**. In [`server/src/routes/companies.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/companies.ts):

```typescript
router.post("/import/preview", async (req, res) => {
  assertBoard(req);
  const body = companyPortabilityPreviewSchema.parse(await resolveImportPayload(req, res));
  assertImportTargetAccess(req, body.target);
  const preview = await portability.previewImport(body);
  res.json(preview);
});

```

*Source: [companies.ts – import preview](https://github.com/paperclipai/paperclip/blob/master/server/src/routes/companies.ts#L106-L112)*

**CLI dry-run:**

```bash
paperclipai company import ./my-company --dry-run

```

### Applying the Import

New company import:

```bash
paperclipai company import ./my-company

```

Existing company import with collision handling:

```bash
paperclipai company import ./my-company \
  --target existing \
  --company-id 123e4567-89ab-cdef-0123-456789abcdef \
  --collision rename

```

The server-side apply logic in [`server/src/routes/companies.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/companies.ts):

```typescript
router.post(COMPANY_IMPORT_ROUTE_PATH, async (req, res) => {
  assertBoard(req);
  const rawImportBody: unknown = await resolveImportPayload(req, res);
  await executeImportRequest(req, res, rawImportBody);
});

```

*Source: [companies.ts – import execution](https://github.com/paperclipai/paperclip/blob/master/server/src/routes/companies.ts#L129-L138)*

## Handling Large Packages: Chunked Transfer Protocol

When packages exceed the inline JSON limit (~48 MiB), Paperclip automatically switches to a **resumable chunked transfer**.

### Chunked Transfer Flow

1. **Declare transfer** — `POST /api/companies/import-transfers` returns a transfer ID and missing parts list
2. **Upload parts** — `PUT /api/companies/import-transfers/:transferId/parts/:partIndex` with SHA-256 verification per chunk
3. **Preview assembled package** — `POST /api/companies/import-transfers/:transferId/preview`
4. **Apply import** — `POST /api/companies/import-transfers/:transferId/apply` (verifies whole-file hash before processing)

The CLI handles this transparently through `resolveChunkedImportZip` and `uploadCompanyImportTransfer` in [`cli/src/commands/client/company.ts`](https://github.com/paperclipai/paperclip/blob/main/cli/src/commands/client/company.ts):

```typescript
// Key functions in cli/src/commands/client/company.ts:
// - resolveInlineSourceFromPath: converts folder/zip to portable JSON
// - resolveChunkedImportZip: decides chunked vs. inline transfer
// - uploadCompanyImportTransfer: orchestrates chunked upload

```

*Source: [company.ts – CLI helpers](https://github.com/paperclipai/paperclip/blob/master/cli/src/commands/client/company.ts#L65-L95)*

## Source Files and Package Format

| File | Purpose |
|------|---------|
| [`server/src/routes/companies.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/companies.ts) | HTTP endpoints for export, import, preview, and chunked transfer (lines ~90-150) |
| [`packages/shared/src/types/company-portability.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/shared/src/types/company-portability.ts) | TypeScript types: `CompanyPortabilityExportResult`, `CompanyPortabilityImportResult` |
| [`packages/shared/src/validators/company-portability.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/shared/src/validators/company-portability.ts) | Zod schemas: `companyPortabilityExportSchema`, `companyPortabilityPreviewSchema` |
| [`cli/src/commands/client/company.ts`](https://github.com/paperclipai/paperclip/blob/main/cli/src/commands/client/company.ts) | CLI implementation, zip handling, transfer orchestration |
| [`doc/plans/2026-03-13-company-import-export-v2.md`](https://github.com/paperclipai/paperclip/blob/main/doc/plans/2026-03-13-company-import-export-v2.md) | Product specification for markdown-first format |
| [`doc/companies/companies-spec.md`](https://github.com/paperclipai/paperclip/blob/main/doc/companies/companies-spec.md) | Canonical package layout specification |

## Summary

- **Export and import company configurations** as versioned, markdown-first packages using `POST /api/companies/:companyId/exports` and `POST /api/companies/import`
- **Preview changes before applying** via `--dry-run` or dedicated preview endpoints to avoid surprises
- **Handle large archives** automatically through Paperclip's chunked transfer protocol with SHA-256 verification
- **Control collision behavior** with `rename`, `skip`, or `replace` strategies when importing into existing companies
- **Require Board-level permissions** for all import operations and company exports

## Frequently Asked Questions

### What permissions are required to export or import a company?

Exports require **CEO or Board member** status on the source company. Imports require **Board member** status system-wide, plus specific access to the target company when importing into an existing organization. These checks are enforced in `assertSameCompanyCeoAgentOrBoard()` and `assertBoard()` middleware in [`server/src/routes/companies.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/companies.ts).

### Can I import a company package into an existing organization without creating duplicates?

Yes. Use the `--target existing --collision rename|skip|replace` flags when importing. The preview endpoint shows exactly which entities will be created, updated, or skipped before you apply changes. The `rename` strategy appends numeric suffixes to conflicting names; `skip` preserves existing values; `replace` overwrites them.

### What happens if my company export is larger than 48 MB?

The CLI automatically detects the size threshold and switches to **chunked transfer mode**. It declares a transfer ID, uploads the zip in verified parts, then assembles the package server-side before running the import preview or apply. This resume-capable protocol prevents network timeouts and supports unreliable connections.