What crm.deal.add does
Creates a deal — a qualified opportunity in a pipeline. Used by integrations that skip or bypass leads: e-commerce orders, booking systems, ERP-originated opportunities, and 'no-lead mode' portals.
Business use cases
- E-commerce or booking platforms creating deals per order/booking
- ERP quotations mirrored as CRM deals
- No-lead-mode capture: qualified inquiries straight to a pipeline
- Renewal/recurring deal generation from subscription systems
- Cross-pipeline handover: won sales deal spawning an onboarding deal
Typical fields and parameters
TITLE— Deal title — include order/reference numbers for list-view scannabilityCATEGORY_ID— Pipeline ID (0 = default). Get IDs from crm.category.list. Wrong pipeline = invisible dealSTAGE_ID— Stage within that pipeline — stage IDs are per-category (e.g. C2:NEW); mismatched pairs fail confusinglyCONTACT_ID / COMPANY_ID— Bindings to person/org. Multiple contacts via crm.deal.contact.items.set after creationOPPORTUNITY + CURRENCY_ID— Amount and currency; set IS_MANUAL_OPPORTUNITY='Y' if product rows shouldn't overwrite itASSIGNED_BY_ID— Responsible userUF_CRM_*— Custom fields — unit reference, order ID, contract type…
Example workflow
- Order confirmed in your e-commerce backend
- Contact resolved: crm.contact.list by phone/email → found ID, or crm.contact.add
- crm.deal.add with CATEGORY_ID for the 'Online Orders' pipeline, CONTACT_ID bound, OPPORTUNITY set
- crm.item.productrow.set attaches purchased items
- Deal ID stored against the order for status sync-back
Example request
POST .../crm.deal.add.json
{
"fields": {
"TITLE": "Order #8842 — Ahmed",
"CATEGORY_ID": 2,
"STAGE_ID": "C2:NEW",
"CONTACT_ID": 512,
"OPPORTUNITY": 4500,
"CURRENCY_ID": "AED",
"ASSIGNED_BY_ID": 7,
"UF_CRM_ORDER_ID": "8842"
},
"params": { "REGISTER_SONET_EVENT": "Y" }
}Example response
{ "result": 3120, "time": { ... } }
// "result" is the new deal ID.Field mapping notes
- STAGE_ID format is C{categoryId}:{stageCode} for non-default pipelines — 'NEW' alone lands in the default pipeline's stage
- Bind contacts at creation where possible; orphan deals break reporting and communication matching
- OPPORTUNITY is overwritten by product-row totals unless IS_MANUAL_OPPORTUNITY is 'Y'
- Keep the external system's ID in a custom field — it is your sync key forever
Security notes
- Deals carry commercial data; scope the integration account's pipeline visibility deliberately
- Validate amounts server-side — never trust client-submitted OPPORTUNITY values
Common errors
- Deal appears in wrong pipeline — STAGE_ID/CATEGORY_ID mismatch — fetch valid pairs from crm.category.list + crm.status.list
- Product rows overwrote the amount — Set IS_MANUAL_OPPORTUNITY='Y' or set amount after rows
- 'Access denied' on a specific pipeline — The integration user lacks rights to that category — permissions are per-pipeline
- Duplicate deals per order — Retry without idempotency — check for existing UF_CRM_ORDER_ID before adding
Production implementation tips
- Search-by-external-ID before create makes your integration safely re-runnable
- Batch deal + product rows + timeline comment into one batch call
- New-deal automations (notifications, tasks) fire on API creation too — design rules knowing half your deals arrive via API
Webhook or OAuth app?
Webhook for internal one-way flows; OAuth app for two-way order/deal sync where token hygiene and user-independence matter over years.
Full decision guide: webhook vs OAuth app in Bitrix24.
When to use a queue worker
Order bursts (sales, campaigns) need queued creation. Serialize per-customer to keep contact resolution race-free.
How Tech Titan can help
Tech Titan builds production Bitrix24 integrations around crm.deal.add and its siblings — with authentication, field mapping, queue workers, retry logic, duplicate handling, and structured logs as standard. If this method is on your critical path, bring the requirement to a free audit call and leave with an architecture sketch.