Transferring a project to another company
A project transfer moves ownership of a project from one production company to another. It’s a three-phase workflow: the originator invites a recipient, the recipient accepts or rejects, and both parties get notified of the outcome.
What happens
Section titled “What happens”sequenceDiagram
actor OriginatorAdmin as Originator (admin)
participant App as Your app
actor RecipientAdmin as Recipient (admin)
OriginatorAdmin->>App: Open project, click Transfer
OriginatorAdmin->>App: Enter recipient contact name + email
App->>RecipientAdmin: Invitation email with link
RecipientAdmin->>App: Open link, log in (or sign up)
RecipientAdmin->>App: Pick target company, accept or reject
alt Accept
App-->>RecipientAdmin: Project appears in their company
App->>OriginatorAdmin: Email — transfer accepted
else Reject
App->>OriginatorAdmin: Email — transfer rejected
end
If the project has a supplier ID, all projects with that supplier ID transfer as a group. This is the most important thing to know before initiating — the producer is transferring a bundle, not just one project.
Phase 1 — Initiating the transfer
Section titled “Phase 1 — Initiating the transfer”The originator’s admin opens a project and starts a transfer.
What they see
Section titled “What they see”A modal form with these fields:
| Field | Translation key |
|---|---|
| Contact name | transfer.initiate.contactName (placeholder: transfer.initiate.contactNamePlaceholder) |
| Contact email | transfer.initiate.contactEmail (placeholder: transfer.initiate.contactEmailPlaceholder) |
| Supplier-ID note (informational) | transfer.initiate.supplierNote |
Plus title transfer.initiate.title and submit button transfer.initiate.submit.
Outcomes
Section titled “Outcomes”| Outcome | Translation key |
|---|---|
| Success | transfer.initiate.success (with the email shown) |
| Already a pending transfer for this project | A toast appears with a link to view the existing invitation |
| Other failure | transfer.initiate.errorGeneric |
Phase 2 — Tracking transfers
Section titled “Phase 2 — Tracking transfers”The originator can view all of their company’s outgoing transfers on a dashboard page.
What they see
Section titled “What they see”| Visible text | Translation key |
|---|---|
| Page title | transfer.dashboard.title |
| Status badges | transfer.status.pending, transfer.status.accepted, transfer.status.rejected, transfer.status.expired, transfer.status.canceled |
| Empty state | transfer.dashboard.emptyState |
The table shows project name, supplier ID, recipient contact, status, when the invitation was sent and last resent, and when it expires.
For pending invitations, two actions are available:
| Action | Translation key |
|---|---|
| Resend the invitation email | transfer.dashboard.resend |
| Cancel the invitation | transfer.dashboard.cancel (with confirmation: transfer.dashboard.cancelTitle + transfer.dashboard.cancelConfirm; success: transfer.dashboard.cancelSuccess) |
A small badge on the projects list (the “pending transfer chip”) indicates which projects have an open invitation. If a transfer spans multiple sibling projects (via supplier ID), each gets the same group letter on the badge.
Phase 3 — Accepting or rejecting
Section titled “Phase 3 — Accepting or rejecting”The recipient opens the invitation email and clicks the link.
What they see
Section titled “What they see”The page they land on depends on whether they’re signed in:
| Situation | What’s shown |
|---|---|
| Not signed in | Description transfer.accept.unauthDescription + login button |
| Signed in but not admin of any company | Error transfer.accept.selectCompany.emptyAdmin |
| Signed in, admin of one or more companies | Description transfer.accept.authDescription, a target-company select (transfer.accept.selectCompany.label), and two buttons: Accept (primary) / Reject (danger) |
On accept, the recipient is redirected to the projects list — and the transferred project (or group) now appears there.
On reject, they see a success message confirming the rejection and are redirected back to projects.
Error states the recipient might see
Section titled “Error states the recipient might see”| Error | Translation key |
|---|---|
| Invitation not found | projectTransfer.errors.notFound.title + body |
| Invitation expired | projectTransfer.errors.expired.title + body |
| Already accepted or rejected | projectTransfer.errors.alreadyCompleted.title + body |
| Generic | projectTransfer.errors.generic.title + body |
What you can customise
Section titled “What you can customise”Translations
Section titled “Translations”All transfer text lives under transfer.* and projectTransfer.errors.* in tep-configuration/translations/{locale}/main/transfer.json. Override per client.
The three transfer emails
Section titled “The three transfer emails”All three transfer notifications can be overridden per client:
| When | Default template | |
|---|---|---|
| Invitation | Originator invites recipient | tep-project-transfer-invitation.mjml |
| Accepted | Recipient accepts | tep-project-transfer-accepted.mjml |
| Rejected | Recipient rejects | tep-project-transfer-rejected.mjml |
Currently only the TEP client has these templates — the project-transfer feature is TEP-only. If you’re CDN, NZ, or Omni you’d need to ship your own templates as part of enabling the feature.
Variations for your deployment
Section titled “Variations for your deployment”| Your deployment | What’s different |
|---|---|
| TEP | Project transfer is enabled; the three templates above are available |
| CDN, NZ, Omni | Project transfer is not currently configured. Enabling it requires shipping the three transfer email templates for your client. |
| Projects with supplier IDs | A transfer applies to all sibling projects sharing that supplier ID (shown as a group badge on the projects list) |
Need more detail?
Section titled “Need more detail?”For the three mutation hooks, the URL-deep-link pattern for existing invitations, the token validation, and the “forwardable invitation” design decision, see Transferring a project (engineering).