I INQUA
Sign in Create account
Guide

How to import Opportunities into Salesforce

The wizard does not support the object, so the first half of this job is choosing a different tool. The second half is getting three required fields and one lookup right.

The short answer: the Data Import Wizard does not support Opportunities. Use Data Loader or the API instead. Your file needs Name, StageName and CloseDate — the only three fields Salesforce marks Required on create — plus AccountId to attach the deal to an account. Write CloseDate as yyyy-MM-dd, and make every StageName an active stage in your org.

Why the Data Import Wizard is out

The wizard imports accounts, contacts, leads, solutions, campaign members, person accounts and custom objects. Opportunity is not on that list, and no setting adds it. It also takes CSV only and caps at 50,000 records per run — limits worth knowing even when your object is supported, and covered in Data Import Wizard limits and workarounds.

So your options are Data Loader (free, from Salesforce, works against the API and can therefore load any object the API exposes), the Bulk API directly, or a third-party tool. Wider comparison in Salesforce import options.

What Salesforce actually requires

Straight from the Opportunity object reference. Three fields are marked Required. Everything else is optional at the API level — which does not mean optional for your business, nor that a validation rule in your org will not demand it anyway.

Field (API name) Type Required on create? What trips people up
Name Text Yes Limit is 120 characters. Longer values are rejected, not truncated.
StageName Picklist Yes Must be a value the field accepts — active, and available to the record type you are loading into.
CloseDate Date Yes Bulk API wants yyyy-MM-dd. Excel will happily hand you 3/7/2026 instead.
AccountId Lookup No — the API allows it to be blank Nearly always wrong to leave blank. An orphan Opportunity rolls up to nothing.
Amount Currency No Once the Opportunity has products, Salesforce derives Amount from them and ignores updates to it.
Probability, ForecastCategoryName Percent, picklist No Defaulted on create from StageName. Leave them out unless you are deliberately overriding.
OwnerId Lookup No Defaults to the user running the load. If you want the real owners, map them.
CurrencyIsoCode Restricted picklist Multi-currency orgs only Must be a currency your org allows — see below.

Note the asymmetry: AccountId is not required by the API, but a missing or wrong one is the failure people actually hit. Salesforce will happily create a headless Opportunity attached to no account.

Linking each Opportunity to its Account

1. The Account's record Id

Put the 18-character Id in an AccountId column. Correct, but you first have to export every Account with its Id and join that back to your source file. Export the 18-character form, not the 15-character one: 15-character Ids are case-sensitive, while Excel's lookup functions are not, so a VLOOKUP can quietly treat 0018d00000AbCdE and 0018d00000abcde as the same key and attach the wrong account to the deal. The 18-character Id carries a checksum suffix precisely so that case-insensitive systems like Excel can handle it safely.

Two different errors come back when the Id is wrong, and they mean different things. A well-formed Id that Salesforce cannot resolve — deleted record, wrong org or sandbox, an Id belonging to a different object — fails as INVALID_CROSS_REFERENCE_KEY. A value that is not a Salesforce Id at all — wrong length, stray characters, a truncated cell — fails earlier as MALFORMED_ID.

2. An External Id on Account (better)

If Account has a custom field with External Id ticked — your CRM's old account number, an ERP key, a domain — Bulk API lets you reference the parent by that key instead of its Salesforce Id, using a RelationshipName.IndexedFieldName column header:

Name,StageName,CloseDate,Account.Legacy_Account_No__c
Northwind renewal,Proposal/Price Quote,2026-09-30,ACC-10041

The relationship name on Opportunity's account lookup is Account, so the header is Account.YourField__c. Two constraints from the Bulk API docs, both worth reading twice:

  • Only indexed fields on the parent qualify. A custom field is indexed if its External Id box is checked; a standard field only if its idLookup property is true.
  • You cannot match Accounts by name. Account.Name has no idLookup, so that header will not work. If your file only has account names, you must resolve them to Ids or an External Id yourself, before the load. There is no way around it.

Child-to-parent only, and one level — you cannot reach a grandparent through this syntax.

Getting StageName and CloseDate past the parser

StageName is a picklist, and a picklist compares strings exactly. Your source system says Proposal; the org says Proposal/Price Quote. A trailing space makes a different string. A stage that is inactive, or not enabled for your record type, still shows in Setup and is still rejected. That family of failures is pulled apart in bad value for restricted picklist field.

CloseDate is a date field, and the Bulk API format for date fields is yyyy-MM-dd. Anything ambiguous — 03/07/2026 is March 7 in the US and 3 July in the UK — is a coin flip at best and a type-conversion error at worst. Dates landing one day early are a separate timezone problem: imported dates are off by one day.

A file that works

Minimum viable insert, using the Account Id directly. Headers must match the field's API name exactly, and the file must be UTF-8:

Name,StageName,CloseDate,AccountId,Amount,Type
Northwind renewal,Proposal/Price Quote,2026-09-30,0018d00000ABCdeAAG,45000,Existing Customer - Upgrade
Contoso pilot,Qualification,2026-08-14,0018d00000XYZfgAAG,12000,New Customer

No Id column — you are inserting, not updating. No Probability — the stage sets it.

The next wall: products and line items

Line items are a second, separate load into OpportunityLineItem — you cannot do it in the same pass. Each row needs:

  • OpportunityId — required, so load the Opportunities first and get their Ids back.
  • PricebookEntryId — required. Not Product2Id: that has been read-only since API version 30.0, and the docs point you to PricebookEntryId instead. A PricebookEntry is a product in a specific price book, so it is a lookup per product per book.
  • Quantity, plus either UnitPrice or TotalPrice. UnitPrice is required when TotalPrice is not specified — but you cannot send both on the same row.

The price book behind that entry must also be the price book on the Opportunity (Pricebook2Id); mismatch them and rows fail with a field-integrity error. If you only need a deal value and not a product breakdown, set Amount and skip all of this — but remember that once an Opportunity has products, Salesforce computes Amount from them and ignores whatever you write there.

Multi-currency orgs

With multi-currency enabled, every Opportunity carries CurrencyIsoCode — a restricted picklist of the ISO codes your org allows. An unlisted code is rejected outright, and if the Opportunity has a price book set, its currency must match the currency of the PricebookEntry records behind its line items.

Where these imports actually fail

What you see What it really is Fix
REQUIRED_FIELD_MISSING A blank Name, StageName or CloseDate — or a column you never mapped Required field missing
Bad value for restricted picklist A stage name your org does not have, or one that is inactive or off the record type Restricted picklist
INVALID_CROSS_REFERENCE_KEY or MALFORMED_ID AccountId resolves to nothing (wrong org, deleted record) — or is not a well-formed Id at all Re-export the 18-character Ids, or switch to an Account External Id header
Cannot convert value to correct data type CloseDate in a local format, or Amount carrying a currency symbol or thousands separator Type conversion
Field integrity exception on line items PricebookEntry is in a different price book, or a different currency, than the Opportunity Align Pricebook2Id and currency first

The full index is at Salesforce import errors.

Doing the preparation before the load, not after it

Every hard part of this job happens before a record is written: resolving account keys, translating stage names, normalizing dates. Data Loader does none of it — it faithfully sends what you give it and hands back a CSV of errors.

That gap is what INQUA fills. It reads your .xlsx or CSV as-is and joins your Opportunity file against an Account export — up to four lookup files, with a match-rate preview, so you see how many rows found an account before you commit. It captures the accepted StageName values from your org's describe and flags every cell a restricted picklist would reject, and its Map values editor lists the distinct stages in your file against a dropdown of the real ones. Dates are parsed with an exact format you specify, so 03/07/2026 stops being ambiguous. Then either insert via Bulk API 2.0 — insert or External-Id upsert only, double-confirmed, never a delete and never an update by record Id — or export a typed .xlsx workbook onto your own load template and run that through Data Loader. It refuses the Salesforce upload while any cell error remains.

Be clear about what that does not buy you. It catches structural problems — wrong types, unknown picklist values, unresolved lookups, missing required columns. It cannot simulate your org: validation rules, Flows, triggers and duplicate rules all still run server-side, and any of them can reject a row that previewed perfectly. Nothing running outside your org can promise otherwise.

It is free during early access, and works with no Salesforce connection at all if you only want a clean, typed file to hand to Data Loader — see how the two compare.

Frequently asked

Can the Data Import Wizard import Opportunities?

No. The Data Import Wizard supports accounts, contacts, leads, solutions, campaign members, person accounts and custom objects. Opportunity is not among them, and no setting adds it. To load Opportunities you need Data Loader, the Bulk API, or a third-party import tool that talks to the API.

What fields are required to insert an Opportunity?

Salesforce marks three fields Required on create: Name, StageName and CloseDate. AccountId is not required by the API — it is nillable — so a file without it will still load, creating Opportunities attached to no account. In practice you almost always want AccountId too, plus whatever your org's validation rules and page layouts demand.

How do I set the Account on an Opportunity without looking up 18-character Ids?

Use an External Id on Account. If a custom Account field has External Id ticked, Bulk API accepts a column header of the form Account.Your_Field__c and resolves the parent by that key. Only indexed fields qualify: custom fields with External Id checked, or standard fields whose idLookup property is true.

Why can't I just put the Account name in the file?

Because Account.Name is not an idLookup field, so it cannot be used as a relationship column header in the Bulk API. Account names are not unique and Salesforce will not guess. You have to resolve names to record Ids or to an External Id before the load — by joining your file against an Account export.

What date format does CloseDate need?

For the Bulk API, date fields use yyyy-MM-dd — so 2026-09-30. Avoid locale-dependent formats like 03/07/2026, which is March 7 in the US and 3 July in the UK. Excel will often reformat dates behind your back, which is why dates are one of the most common causes of type-conversion errors on import.

How do I import Opportunity products or line items?

As a separate second load into OpportunityLineItem, after the Opportunities exist. Each line needs OpportunityId and PricebookEntryId, both required, plus Quantity and either UnitPrice or TotalPrice. Product2Id is read-only from API version 30.0 onward, so you must resolve each product to a PricebookEntry in the price book assigned to the Opportunity.

Will an import tool stop my Opportunity rows from being rejected?

Only the structural rejections. A good tool catches wrong data types, stage names the picklist does not accept, unresolved account lookups and missing required columns before anything is written. It cannot simulate your org, so validation rules, Flows, triggers and duplicate rules still run on the server and can still reject a row that previewed cleanly.