CRM migration

Migrate from OPEX 365 CRM to Twenty CRM

Field-level mapping, validation, and rollback between OPEX 365 CRM and Twenty CRM. We move data and schema; workflows are rebuilt natively in Twenty CRM.

OPEX 365 CRM logo

OPEX 365 CRM

Source

Twenty CRM

Destination

Twenty CRM logo

Compatibility

64%

7 of 11

objects map 1:1 between OPEX 365 CRM and Twenty CRM.

Complexity

BStandard

Timeline

3-5 weeks

Rollback included Accuracy guarantee Field-level validation

Overview

What this migration involves

Moving from OPEX 365 CRM to Twenty CRM is a structural migration across fundamentally different platforms: OPEX 365 CRM runs on Microsoft Dataverse with Azure Active Directory integration, tiered per-user licensing, and separate Sales and Customer Service modules; Twenty CRM is an open-source TypeScript application backed by PostgreSQL with a per-seat cloud tier at $9-$19/user and a free self-hosted option. The migration requires extracting from the Dataverse API (with its service protection limits, polymorphic activityparty relationships, and base64-encoded annotation records), transforming the data to Twenty's Company, Person, and Opportunity objects, and importing through the GraphQL API with a 100/minute rate limit on Pro tier. Workflows, automations, and security roles from OPEX 365 CRM do not migrate; we deliver a written inventory of every active workflow and automation requiring manual rebuild in Twenty. Implementation cost relief is immediate: OPEX 365 CRM implementations routinely cost $5,000 to over $150,000 in partner consulting fees; Twenty eliminates that entire category.

Field-level fidelity

Every standard and custom field arrives verified.

Schema-aware mapping

AI proposes the map; you confirm before any record moves.

Relationships preserved

Parent–child, lookups, and ownership stay linked.

Full activity history

Calls, emails, meetings — with original timestamps.

Attachments & notes

Documents, uploads, and inline notes move with the record.

Why teams make this switch

Two sides of the same decision

Leaving

OPEX 365 CRM logo

OPEX 365 CRM

What's pushing teams away

  • Steep implementation and customization costs ranging from $5,000 to over $150,000 depending on scope, with consulting rates of $150-$250 per hour.
  • Complex licensing model with separate tiers for Sales, Customer Service, and add-on capabilities makes total cost of ownership difficult to predict upfront.
  • Limited integration with non-Microsoft products requires third-party connectors or custom API development for every external system.
  • Steep learning curve for sales teams accustomed to simpler CRM interfaces, with significant training investment required for adoption.
  • Customization complexity grows over time as organizations add workflows and plugins, making system maintenance increasingly dependent on technical specialists.

Choosing

Twenty CRM logo

Twenty CRM

What's pulling them in

  • Top open-source CRM on GitHub with 40.6K stars, giving teams full source code access and infrastructure ownership without per-feature licensing surprises.
  • Free self-hosting under AGPL-3.0 means unlimited users and custom objects for the cost of cloud infrastructure alone, typically $20–100/month.
  • Pricing page explicitly mocks competitors for charging add-on fees for API access, webhooks, and workflows — transparency that resonates with RevOps teams burned by Salesforce.
  • Unlimited custom objects and fields with no price impact, letting teams shape the data model to their business rather than forcing business into rigid schemas.
  • Modern TypeScript/React/PostgreSQL stack means developer-led teams can extend, self-host, or integrate without fighting legacy architecture.

Object mapping

How OPEX 365 CRM objects map to Twenty CRM

Each row shows how a OPEX 365 CRM object lands in Twenty CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.

Typical mapping — final map is confirmed during the sample migration step.

OPEX 365 CRM

Contact

maps to

Twenty CRM

Person

1:1
Fully supported

OPEX 365 CRM Contact records map to Twenty Person objects. We map fullname, emailaddress1, telephone1, address fields, and lifecycle-related properties to their Twenty equivalents. Owner assignment resolves by email match against Twenty workspace members. If the customer's OPEX 365 CRM uses custom contact properties (e.g., custom fields from Dataverse), we create matching custom fields in Twenty's Data Model before import using the Metadata API. The Person.recordId is stored for use as a lookup target by activity and opportunity records.

OPEX 365 CRM

Account

maps to

Twenty CRM

Company

1:1
Fully supported

OPEX 365 CRM Account records map to Twenty Company objects. We map name, website, industry, numberofemployees, annualrevenue, address fields, and custom account properties. Account is created before any Person import so that the Person.companyId lookup is satisfied at the moment of Person insert. The company record is also the dedupe key for parent-child hierarchy preservation.

OPEX 365 CRM

Opportunity

maps to

Twenty CRM

Opportunity

1:1
Fully supported

OPEX 365 CRM Opportunity records map to Twenty Opportunity objects. Pipeline stage labels and deal amount migrate directly. We preserve estimatedclosedate, closeprobability (computed from stage mapping), and opportunity type. The opportunity.personId and opportunity.companyId lookups resolve to the migrated Person and Company records respectively. Stage names are stored as-is; the customer's admin recreates pipeline stages in Twenty after migration.

OPEX 365 CRM

Lead

maps to

Twenty CRM

Person (merged)

many:1
Fully supported

OPEX 365 CRM Lead records that are unqualified prospects (not yet converted to Contact) map to Twenty Person records. Leads that have already converted in OPEX 365 CRM are handled as their target object type (Contact or Account). Where the customer uses Leads as a separate queue, we flag the unconverted Lead count during scoping and either migrate them as Person records with a lead_source property or recommend recreating them as a custom Pipeline view. The choice is made during scoping based on the customer's process.

OPEX 365 CRM

Cases (Incident)

maps to

Twenty CRM

Custom Object or Comment

lossy
Fully supported

OPEX 365 CRM Cases (incident entity) have no direct standard equivalent in Twenty CRM. We map the incident to a custom object (e.g., SupportCase) created via Twenty's Metadata API before migration, with fields for case number, status, priority, subject, originating contact, and account. If Twenty's standard Comments model on Person or Company is sufficient for the customer's support workflow, we migrate Cases as Comments linked to the corresponding Person or Company record instead.

OPEX 365 CRM

Activity (emails, calls, tasks, appointments)

maps to

Twenty CRM

Task

1:1
Fully supported

OPEX 365 CRM Activities (activitypointer records) map to Twenty Task objects. The polymorphic activityparty references are resolved to the target Person or Company ID during transformation. We preserve activity type (email, call, task, meeting), timestamp, subject, description, duration (for calls), and outcome. TaskAssignee resolves to the migrated Owner/User. Activity records with no resolvable target party are flagged for manual assignment review post-migration.

OPEX 365 CRM

Note (annotation)

maps to

Twenty CRM

Task (Note subtype)

1:1
Fully supported

OPEX 365 CRM Notes stored as annotation entities with base64-encoded file content require separate extraction using the Dataverse RetrieveContent discharge API. We extract binary attachment bodies to staging blob storage, then remap them as file references on Twenty Task records of note type. The note body text migrates as the Task description, and any file attachments are uploaded to Twenty's attachment storage and linked to the parent record (Person, Company, or Opportunity). This is a distinct extraction step from the standard record migration.

OPEX 365 CRM

Product

maps to

Twenty CRM

Custom Object (Product)

lossy
Fully supported

OPEX 365 CRM Product records with pricing linked via productpricelevel entities map to a custom Product object in Twenty created via the Metadata API. Product name, SKU, and pricing tier information migrate with pricing stored as custom fields. Bundle structures are noted as a separate reassembly task for the customer's admin post-migration since Twenty's standard Opportunity model does not include line-item bundles.

OPEX 365 CRM

User (owner)

maps to

Twenty CRM

Workspace Member

1:1
Fully supported

OPEX 365 CRM User records map to Twenty workspace members by email address match. Owner assignments on Contact, Account, Opportunity, and Activity records resolve to the corresponding Twenty user. Any OPEX 365 CRM owner with no matching email in the Twenty workspace goes to a reconciliation queue; the customer provisions the missing user before record import resumes. Inactive OPEX 365 CRM users can be migrated as inactive Twenty members or archived with their record assignments reassigned.

OPEX 365 CRM

Custom Entity (Dataverse)

maps to

Twenty CRM

Custom Object

1:1
Fully supported

OPEX 365 CRM custom entities discovered via the Dataverse EntityDefinitions endpoint map to Twenty custom objects created via the Metadata API. We enumerate all custom entity schemas during pre-migration discovery, generate matching field definitions with type conversion (Dataverse OptionSet becomes Twenty select, Dataverse Lookup becomes Twenty relation, etc.), then import the data. Lookup relationships between custom entities and standard entities (Contact, Account) are preserved by resolving the parent record ID before the child record inserts.

OPEX 365 CRM

Pipeline and Stage configuration

maps to

Twenty CRM

Pipeline configuration

lossy
Fully supported

OPEX 365 CRM pipeline and stage metadata does not migrate automatically and is not transferred as code. We document the source pipeline structure (pipeline names, stage labels, stage order, stage probabilities) in a written configuration guide. The customer's admin recreates these in Twenty's pipeline settings after migration. Closed-won and closed-lost stage mappings are preserved in the documentation for accurate reporting continuity.

Gotchas + challenges

What specifically takes care here

Platform-specific issues from each side, plus the pair-specific challenges that don't show up on either platform's page on its own.

OPEX 365 CRM logo

OPEX 365 CRM gotchas

Medium

Dataverse API rate limits vary by license tier

Medium

Custom entity schemas require manual enumeration

High

Activity Party relationships are polymorphic and fragile

Low

Legacy attachment storage requires separate extraction

Twenty CRM logo

Twenty CRM gotchas

High

Import order is enforced and critical

High

Export limited to 20,000 records and visible columns only

Medium

Soft-deleted records count toward uniqueness and trigger restores

Medium

API rate limits cap at 200 req/min on Organization tier

Low

No native email sequences — follow-up cadences require external tools

Pair-specific challenges

  • Polymorphic activityparty requires pre-migration party resolution

    OPEX 365 CRM stores all Activities (emails, calls, meetings, tasks) as activitypointer records with a polymorphic activityparty relationship. The partyid field can reference a Contact, Account, Lead, or User with no type discriminator in the record itself. Twenty CRM uses explicit relation fields (personId, companyId) on Task objects. Before any activity data moves, we run a referential integrity pass that resolves every activityparty reference to its correct target type and the corresponding migrated record ID in Twenty. Any activityparty referencing a Contact or Account that did not migrate (or was not found) gets flagged and held in a review queue. Skipping this step results in orphaned activity assignments where the activity exists in Twenty but has no linked Person or Company.

  • Custom fields must exist in Twenty before CSV import

    Twenty's CSV import creates records, not fields. Any OPEX 365 CRM custom fields must be pre-created in Twenty's Data Model (Settings -> Data Model) before the migration script attempts to map data into them. We run a pre-migration schema discovery scan against the Dataverse EntityDefinitions endpoint to enumerate all custom attributes, then create matching Twenty custom fields via the Metadata API before any record import begins. If this step is skipped, custom field data silently drops during import because the target field does not exist in Twenty yet.

  • Annotation attachment bodies require separate extraction

    Notes and email attachments in OPEX 365 CRM are stored as annotation entities with base64-encoded file content. The standard Dataverse API export does not include attachment bodies by default. We extract annotation records separately using the Dataverse RetrieveContent discharge API and store binary content in our staging blob storage. During Twenty import, we upload files to Twenty's attachment storage and link them to the corresponding Task or Note record. This adds a distinct extraction phase to the migration sequence and must be sequenced after Person and Company records exist so that the parent lookup is valid.

  • Twenty API rate limits cap import throughput

    Twenty's API enforces a rate limit of 100 requests per minute on the Pro tier and 200 requests per minute on the Organization tier. Migrations with large record volumes (over 50,000 total records) require chunking and pacing to stay within this limit. We implement request-level backoff and chunking in our import pipeline, batching records into groups of 50-100 per request. For migrations exceeding 200,000 records, we recommend upgrading to the Organization tier for the higher rate limit before migration day or scheduling the migration in off-peak hours.

  • Self-hosted Twenty deployments need Docker infrastructure validation

    Twenty requires Docker and Docker Compose for self-hosted deployments. Organizations running self-hosted Twenty should validate that their infrastructure meets the requirements (Linux host, Docker Engine, sufficient storage for PostgreSQL and file attachments) before migration day. Cloud-hosted Twenty removes this requirement at the Organization tier. We do not migrate the self-hosted infrastructure itself; we migrate the data layer. If the customer is migrating from OPEX 365 CRM to self-hosted Twenty, the Docker environment setup is a separate provisioning step outside migration scope.

Migration approach

Six steps for a successful OPEX 365 CRM to Twenty CRM data migration

  1. Schema discovery and scoping

    We audit the OPEX 365 CRM environment through the Dataverse API, enumerating all standard and custom entity schemas via the EntityDefinitions endpoint. We capture object counts, custom field definitions, owner assignments, pipeline and stage configurations, and activityparty relationship patterns. We pair this with a Twenty workspace readiness assessment: verifying the self-hosted or cloud deployment URL, confirming workspace creation, and checking that the Data Model settings page is accessible for custom field creation. The discovery output is a written migration scope with object counts, a preliminary field mapping document, and a Twenty Data Model creation checklist.

  2. Twenty Data Model preparation

    We create all custom objects and custom fields in Twenty via the Metadata API before any data moves. This includes custom objects for Support Cases, any Dataverse custom entities, and all custom fields on Person, Company, and Opportunity. We also invite all team members to the Twenty workspace at this stage so that owner lookups (personId, companyId) can resolve at migration time. Workspace members must accept their invitations and exist in Twenty before the record import begins; otherwise owner assignments cannot be mapped and records land unassigned.

  3. Field mapping and data quality pass

    We build the complete field mapping document mapping every OPEX 365 CRM Dataverse attribute to its Twenty equivalent, with type conversion rules (OptionSet values become select options, lookup fields become relation IDs, date fields normalized to ISO 8601). We run a data quality pass identifying duplicates, incomplete records, and orphaned activityparty references. Records that fail quality thresholds are flagged for customer review before migration. The mapping document is validated against Twenty's actual schema (created in Step 2) to catch any missing field definitions before extraction begins.

  4. Dataverse extraction with rate-limit handling

    We extract records from OPEX 365 CRM using the Dataverse REST API with service protection limit handling. We pace extraction jobs using retry-after headers, chunk large record sets into batches of 200-300 records per request, and back off exponentially when rate limits are hit. Annotation records (Notes and attachments) are extracted separately using the RetrieveContent discharge API and stored in staging blob storage with a reference map linking each annotation to its parent record ID. The extraction sequence follows dependency order: Users and Owners first, then Accounts (as Company), then Contacts (as Person), then Opportunities, then Activities, then Custom Entities, then annotation files.

  5. Transform, validate, and Twenty import

    We transform extracted records to Twenty's GraphQL input format, applying field mapping rules, type conversions, and owner ID resolution. Activity records are processed through the polymorphic party resolution logic, with any unresolved references held in a review queue. We import records in dependency order (Company before Person, Person before Opportunity, Person/Company before Task) using Twenty's REST or GraphQL API with chunking and exponential backoff to respect the 100/minute (Pro) or 200/minute (Organization) rate limit. Annotation files are uploaded to Twenty's attachment storage and linked to their parent Task records after the parent record is confirmed in Twenty.

  6. Reconciliation, cutover, and handoff

    We run a row-count reconciliation comparing source object counts to destination record counts for every object class. We spot-check 25-50 records against the OPEX 365 CRM source to validate field accuracy, relationship integrity, and timestamp preservation. Any orphaned activityparty records held in the review queue are resolved manually with the customer's input. We deliver the Pipeline and Stage configuration guide for the customer's admin to recreate in Twenty's settings. We do not rebuild OPEX 365 CRM workflows, plugins, or security roles; these are documented in the migration scope and rebuilt by the customer's admin or a Twenty implementation partner as a separate engagement.

Platform deep dives

Context on both ends of the pair

OPEX 365 CRM logo

OPEX 365 CRM

Source

Strengths

  • Native Azure Active Directory and Microsoft 365 identity integration with no additional identity provider configuration required.
  • Unified data model across ERP, CRM, and Power Platform through Microsoft Dataverse reduces data silos within the Microsoft ecosystem.
  • AI-powered features including predictive forecasting and lead scoring available in Sales Premium and Customer Service Premium tiers.
  • Microsoft Dynamics 365 Sales Professional at $65/user/month undercuts comparable Salesforce tiers significantly for Microsoft-aligned organizations.

Weaknesses

  • Implementation typically requires certified Microsoft partners with consulting engagements running $150-$250/hour.
  • Non-Microsoft integrations demand separate connectors or custom API work, adding cost and maintenance overhead.
  • Licensing tiers are granular and poorly documented, making it difficult to predict total spend without a detailed requirements analysis.
  • Workflow and plugin customization accumulates technical debt that becomes expensive to maintain during upgrades.
Twenty CRM logo

Twenty CRM

Destination

Strengths

  • AGPL-3.0 open-source license with full source code on GitHub — no vendor lock-in, no sunset risk.
  • Unlimited users and unlimited custom objects on self-hosted, with no feature gating based on headcount.
  • REST and GraphQL APIs available on all paid tiers, not locked behind an enterprise add-on fee.
  • MCP server and webhooks shipped as standard features, not premium upgrades.
  • Modern PostgreSQL-backed data model that developer teams can query, extend, and self-host.

Weaknesses

  • Recent v1.0 release means limited production hardening compared to CRMs with multi-year operational track records.
  • No native email sequencing or sales engagement tools — follow-up cadences require a separate platform.
  • No native two-way email sync or inbox integration, requiring third-party connectors for full activity logging.
  • Self-hosting 'free' pricing hides real infrastructure and DevOps costs that stack up over time.
  • Workflow automation is functional but lacks the complexity needed for sophisticated multi-step sales motions.

Complexity grading

How hard is this migration?

Standard CRM migration. 3 of 8 objects need a mapping; the rest are 1:1.

B

Overall complexity

Standard migration

Derived from compatibility, mapping clarity, API constraints, and data volume across OPEX 365 CRM and Twenty CRM.

  • Object compatibility

    B

    3 of 8 objects need a mapping; the rest are 1:1.

  • Field mapping clarity

    C

    Field mapping is derived from defaults — final spec confirmed during the sample migration.

  • Timeline complexity

    B

    8-object category — typical timelines run 2–7 days end-to-end.

  • API constraints

    B

    OPEX 365 CRM: Varies by license tier and environment; not publicly documented for all tiers.

  • Data volume sensitivity

    A

    OPEX 365 CRM exposes a bulk API — large-volume migrations stream efficiently.

Estimator

Estimate your OPEX 365 CRM to Twenty CRM migration cost

Rule-based pricing — no per-record fees, no manual quotes. Migrations over 2M records are scoped individually.

Step 1

What are you migrating?

Pick a category, then your source and destination platforms.

Category

FAQ

Frequently asked questions about OPEX 365 CRM to Twenty CRM data migrations

Answers to the questions buyers ask most during OPEX 365 CRM to Twenty CRM migration scoping. Not seeing yours? Book a call.

Can't find your answer?

Walk through your OPEX 365 CRM to Twenty CRM migration with a real engineer — 30 minutes, free, written quote within 24 hours.

Book a free 30 minute consultation

Migrations under 15,000 Contacts, 3,000 Accounts, and no custom entities land between three and five weeks. Migrations with multiple Dataverse custom entities, large activity histories (over 200,000 activity records), or Cases requiring custom object creation move to seven to eleven weeks because of the schema discovery, Data Model preparation, and activityparty resolution work. The Twenty workspace preparation and Data Model creation step is the critical path item; it must be complete before any record import can begin.

Adjacent paths

Related migrations to explore

Ready when you are

Move from OPEX 365 CRM.
Land in Twenty CRM, intact.

Tell us record counts and timeline. We'll come back with a written quote inside 1 business day — no commitment, no sales pitch.

Accuracy guarantee Rollback included Quote in 1 business day