CRM migration
Field-level mapping, validation, and rollback between Thryv and Odoo CRM. We move data and schema; workflows are rebuilt natively in Odoo CRM.
Thryv
Source
Odoo CRM
Destination
Compatibility
10 of 14
objects map 1:1 between Thryv and Odoo CRM.
Complexity
BStandard
Timeline
3-5 weeks
Overview
Moving from Thryv to Odoo CRM is a structural migration. Thryv's flat Company structure separates Clients from Companies at the same level, while Odoo uses a unified res.partner model with a company_type field distinguishing individuals from organizations, and address contacts are child records of the company partner. We resolve that schema difference during scoping and use parent_id lookups in Odoo to reconstruct the relationship. Appointment records from Thryv map to Odoo calendar.event with organizer, partner_ids, and duration preserved. Invoice records map to Odoo account.move with line items and payment status carried forward as custom fields. Thryv's Automation Builder and freeform tagging system do not migrate; we deliver a written inventory of every active automation and a normalized tag list for the customer to rebuild in Odoo Studio and assign to res.partner.category. Odoo's REST API and XML-RPC endpoints handle the extraction; we use the xmlrpc/2/common and xmlrpc/2/object endpoints with batch chunking and exponential backoff.
Every standard and custom field arrives verified.
AI proposes the map; you confirm before any record moves.
Parent–child, lookups, and ownership stay linked.
Calls, emails, meetings — with original timestamps.
Documents, uploads, and inline notes move with the record.
Why teams make this switch
Leaving
What's pushing teams away
Choosing
What's pulling them in
Object mapping
Each row shows how a Thryv object lands in Odoo CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
Thryv
Client
Odoo CRM
res.partner
1:1Thryv Clients map to Odoo res.partner with company_type = 'person'. Standard fields (name, email, phone, street, city, state, zip, country) migrate directly. Mobile phone maps to partner.mobile. We preserve all Thryv custom field values as x_thryv_ prefixed custom fields on res.partner. Tag assignments migrate via res.partner.category_id many2many after tag normalization. Thryv Client IDs are stored in x_thryv_client_id for dedupe validation on subsequent delta migrations.
Thryv
Company
Odoo CRM
res.partner (company type) + res.partner (child addresses)
1:manyThryv's flat Company structure (separate from Client) maps to Odoo res.partner with company_type = 'company'. The company contact becomes the parent partner, and any Thryv Company address fields map to child res.partner records with parent_id pointing to the company partner. This reconstructs the Odoo hierarchical address model where individual contacts at the same company share a parent. We use the Thryv Company ID as x_thryv_company_id on the parent partner for reconciliation.
Thryv
Client-Company association
Odoo CRM
res.partner.parent_id
lossyThryv Clients can be associated with Companies via a relationship field. In Odoo, res.partner.parent_id carries this association. We extract the client-company linkage from Thryv's relationship table during data profiling, resolve the parent Thryv Company to its migrated res.partner ID, and write parent_id on each client partner during migration. Clients without an associated Company have no parent_id set (they remain standalone contacts).
Thryv
Opportunity
Odoo CRM
crm.lead (Opportunity stage)
1:1Thryv Opportunities map to Odoo crm.lead records with type = 'opportunity'. The Thryv pipeline stage names map to Odoo stage_id values via a stage-mapping table we create during scoping. Deal value, expected close date, and probability migrate to Odoo's expected_revenue, date_deadline, and probability fields. Owner assignment uses email-based User lookup against res.users.
Thryv
Opportunity Stage
Odoo CRM
crm.stage
lossyThryv custom pipeline stages map to Odoo crm.stage records within the relevant team. We preserve Thryv stage order (sequence) and probability percentages. Lost reasons from Thryv custom fields map to Odoo's lost_reason_id if the crm_lost_reason module is installed; otherwise they become a note on the crm.lead record.
Thryv
Appointment
Odoo CRM
calendar.event
1:1Thryv Appointments map to Odoo calendar.event with start (date + time), stop (calculated from duration), duration, and name preserved. The assigned staff member resolves to an Odoo res.users record by email. Attendee contacts resolve to calendar.attendee records linked to the event. Recurring appointment series are flattened into individual calendar.event records during migration because Odoo handles recurring events via calendar.recurrence rather than as a series reference.
Thryv
Invoice
Odoo CRM
account.move
1:1Thryv Invoices map to Odoo account.move with move_type = 'out_invoice' for sent invoices. Line items migrate to account.move.line records with product, quantity, price_unit, and tax handling. Thryv payment status (paid, unpaid, partial) maps to Odoo payment_state. Because Odoo requires a Journal configured for invoicing, we create or identify the appropriate sales journal during schema setup. Invoice PDFs are stored as Odoo ir.attachment linked to the account.move record.
Thryv
Invoice line item
Odoo CRM
account.move.line
1:1Thryv Invoice line items map to Odoo account.move.line with product_id resolved to an Odoo product.product record. If the Thryv product name does not match an existing Odoo product, we create a minimal product.product placeholder during migration so line item references are intact. Discount amounts and tax codes from Thryv map to discount and tax_ids on the Odoo line.
Thryv
Tag
Odoo CRM
res.partner.category
lossyThryv freeform tags on Client records are collected, deduplicated, and normalized into Odoo res.partner.category records during a pre-migration tag audit. Each unique Thryv tag becomes a category with the original tag name as name. During Client migration, res.partner.category_id is populated via the res.partner.category_id many2many relation. Tags with duplicate names (case variations, plural/singular) are merged into a single category during normalization.
Thryv
Custom field (Pro/Max)
Odoo CRM
ir.model.fields (x_ prefixed custom fields)
1:1Thryv custom fields migrate to Odoo custom fields on res.partner (for Client/Company fields) or crm.lead (for Opportunity fields). Field types are matched: Thryv text fields become char, long text become text, date fields become date, number fields become float or integer. We check Odoo edition limits during schema design; Odoo does not impose a field count ceiling at the level Thryv does (100 Pro, 150 Max), so custom field migration is not constrained by edition on the Odoo side.
Thryv
User (Staff/Owner)
Odoo CRM
res.users
1:1Thryv User records (staff and owners) map to Odoo res.users via email match. The customer's Odoo admin provisions res.users before migration begins. We flag any Thryv Owner referenced on Opportunities who has no matching res.users in the reconciliation queue and hold Opportunity migration for those records until the admin provisions the user or reassigns the Owner.
Thryv
Email/SMS log
Odoo CRM
mail.message
1:1Thryv Email and SMS communication logs (available on Keap tier) migrate to Odoo mail.message records linked to the res.partner via model = 'res.partner' and res_id pointing to the partner ID. Message body, direction (inbound/outbound), and timestamp migrate. Thryv's SMS thread structure maps to separate mail.message records within the same thread grouped by subject or conversation ID.
Thryv
Social post (Marketing Center)
Odoo CRM
mail.message
1:1Thryv Marketing Center social posts are exported as mail.message records with a custom subtype and platform metadata (Facebook, Instagram, etc.) stored in extra fields. The post content, scheduling metadata, and performance metrics (likes, shares, impressions) migrate as structured fields on the message record. Platform-native posts are not recreated in Odoo; content is delivered as a data record for manual reposting.
Thryv
Form response
Odoo CRM
crm.lead
1:1Thryv website form submissions are mapped to Odoo crm.lead with type = 'lead'. Form field data populates lead name (from submitted name field), contact_email, contact_phone, and any custom field values. The form submission date becomes the lead create_date. These records land in the Odoo CRM pipeline for follow-up rather than as partner records, preserving the lead qualification workflow.
| Thryv | Odoo CRM | Compatibility | |
|---|---|---|---|
| Client | res.partner1:1 | Fully supported | |
| Company | res.partner (company type) + res.partner (child addresses)1:many | Fully supported | |
| Client-Company association | res.partner.parent_idlossy | Fully supported | |
| Opportunity | crm.lead (Opportunity stage)1:1 | Fully supported | |
| Opportunity Stage | crm.stagelossy | Fully supported | |
| Appointment | calendar.event1:1 | Fully supported | |
| Invoice | account.move1:1 | Fully supported | |
| Invoice line item | account.move.line1:1 | Fully supported | |
| Tag | res.partner.categorylossy | Fully supported | |
| Custom field (Pro/Max) | ir.model.fields (x_ prefixed custom fields)1:1 | Fully supported | |
| User (Staff/Owner) | res.users1:1 | Fully supported | |
| Email/SMS log | mail.message1:1 | Fully supported | |
| Social post (Marketing Center) | mail.message1:1 | Fully supported | |
| Form response | crm.lead1:1 | Fully supported |
Gotchas + challenges
Platform-specific issues from each side, plus the pair-specific challenges that don't show up on either platform's page on its own.
Thryv gotchas
XML-RPC API sunset breaks existing integrations
Custom field limits vary by edition and block installs
Automation workflows cannot be exported
Bounce rate limits affect email campaign recovery
ThryvPay payment processor lock-in
Odoo CRM gotchas
Odoo.sh version gating blocks assisted migrations from trial
Enterprise modules fail to install on Community after database restore
Custom module view inheritance breaks between Odoo major versions
Custom fields risk losing their application context on Community
API access for Community is gated behind the Custom Plan
Pair-specific challenges
Migration approach
Discovery and data audit
We audit the Thryv account across edition (Marketing Center, Keap, Kickstart, Ignite), API endpoint availability (XML-RPC vs REST v2 coverage per object), record counts for Clients, Companies, Opportunities, Appointments, Invoices, Tags, and custom fields. We also document active Automation Builder workflows by walking through the UI with the customer. The discovery output is a written migration scope, a Thryv API availability report, and a list of automation workflows requiring rebuild.
Tag normalization and custom field catalog
We run a tag deduplication pass across all Thryv Client tags, producing a normalized res.partner.category list for Odoo. Simultaneously, we catalog every Thryv custom field by object (Client, Company, Opportunity), field type, and edition limit. We cross-reference custom field names against Odoo standard field names to avoid conflicts and produce a custom field creation manifest for Odoo Studio.
Partner hierarchy mapping and scoping decision
We review every Thryv Company-Client relationship and determine the mapping strategy for each: standalone company partner (no parent), or company parent with child contact partners. We present this as a mapping table to the customer for sign-off before any data is extracted. We also map Thryv pipeline stages to Odoo crm.stage records and configure the sales team and team member assignments.
Schema deployment and sandbox migration
We create the Odoo custom fields, res.partner.category records, crm.stage entries, and any required product.product placeholders in a staging Odoo database (Sandbox or test database). We run a full migration of a representative sample (typically 500-1,000 records per object) and deliver a reconciliation report showing record counts, field coverage, and any import errors. The customer spot-checks migrated records and approves before production migration begins.
Production migration in dependency order
We run production migration in record-dependency order: res.partner.category (tags), res.partner (Companies as company-type), res.partner (Clients with parent_id resolved), crm.lead (Opportunities with partner_id and user_id resolved), calendar.event (Appointments with attendee resolution), account.move (Invoices with partner_id and journal_id), mail.message (Email/SMS logs with partner resolution), crm.lead (Form responses as leads). Each phase emits a row-count reconciliation report before the next phase begins. Owner reconciliation (User lookup) is validated before Opportunities phase.
Cutover, validation, and automation handoff
We freeze Thryv write access during the final delta window, migrate any records modified since the last extraction, then mark Odoo as the system of record. We deliver the Automation Builder inventory document with Odoo Automated Action recommendations, the normalized tag list with category IDs, and the custom field manifest with Odoo field names. We support a one-week hypercare window for reconciliation issues. We do not rebuild Thryv automations as Odoo server actions inside the migration scope.
Platform deep dives
Thryv
Source
Strengths
Weaknesses
Odoo CRM
Destination
Strengths
Weaknesses
Complexity grading
Standard CRM migration. 1 of 8 objects need a mapping; the rest are 1:1.
Overall complexity
Standard migration
Derived from compatibility, mapping clarity, API constraints, and data volume across Thryv and Odoo CRM.
Object compatibility
1 of 8 objects need a mapping; the rest are 1:1.
Field mapping clarity
Field mapping is derived from defaults — final spec confirmed during the sample migration.
Timeline complexity
8-object category — typical timelines run 2–7 days end-to-end.
API constraints
Thryv: Not publicly documented.
Data volume sensitivity
Thryv doesn't expose a bulk API — REST + parallelization used for high-volume runs.
Estimator
Rule-based pricing — no per-record fees, no manual quotes. Migrations over 2M records are scoped individually.
Step 1
Pick a category, then your source and destination platforms.
Category
FAQ
Answers to the questions buyers ask most during Thryv to Odoo CRM migration scoping. Not seeing yours? Book a call.
Walk through your Thryv to Odoo CRM migration with a real engineer — 30 minutes, free, written quote within 24 hours.
Book a free 30 minute consultationAdjacent paths
Other ways to leave Thryv
Other ways to arrive at Odoo CRM
Ready when you are
Tell us record counts and timeline. We'll come back with a written quote inside 1 business day — no commitment, no sales pitch.