VICIDIAL / SALESFORCE DESIGN-CONTRACT WORKBOOK — 2026-11-06

This is a filled design exercise and acceptance plan, not a deployed connector.
No Salesforce token, tenant, API operation or live synchronization is supplied
or claimed. SF_LEAD_A and the other SF_* values are aliases, not usable API IDs.

1. Read field-mapping-fictional.csv. Name the owner of each field and whether it
   is read-only or writable in each direction. Replace assumptions with your
   reviewed schema; an agent web-form link is separate from a record-sync job.
2. Read page-1-fictional.json and page-2-fictional.json as one query result.
   The first page has done=false and a nextRecordsUrl; the second has done=true.
   Three records must be accounted for. Fetching only page1 omits SF_LEAD_C.
   The next-records path is a fixture label, not a callable Salesforce locator.
3. Read identity-map-fictional.csv and run-ledger-fictional.csv. SF_LEAD_A maps
   to1001. The fictional create for SF_LEAD_B timed out; a subsequent identity
   lookup found1002, so the request is reconciled rather than blindly created
   again. SF_LEAD_C has a missing phone and is quarantined without a write.
4. Compare expected-reconciliation.json:3 fetched =2 mapped +1 quarantined,
   zero unresolved, no identity collision. This is an invented worked outcome.
   A real checkpoint advances only after accepted mappings and quarantine
   decisions for the page are durable, not when the HTTP response first arrives.
5. Complete acceptance-checklist.csv for your sandbox. Every row needs actual
   expected/observed evidence and an owner before this design becomes a tested
   integration. Keep a time window and the exact API/schema versions with it.

IDENTITY AND WRITE RULES
Persist a bridge keyed by Salesforce org+object+record ID and by VICIdial
instance+lead ID. A phone number is not a cross-system primary key. An external
reference in vendor_lead_code is useful only after length/uniqueness/conflict
behavior is verified; that field alone does not enforce a one-to-one mapping.

For call outcomes, store append-only events using a reviewed event identity
such as source instance+call identity+event kind. An external ID on a dedicated
Salesforce Call_Event__c object can support upsert after the field is created
and made unique in the sandbox. That custom object/field is YOUR schema design,
not a standard Salesforce object this workbook assumes already exists.
Identical repeat -> same event. Same identity with changed payload -> review
correction policy. A late event must not blindly overwrite a newer Lead status.

PAGINATION AND RESPONSE CONTRACT
Use a REST API version actually supported by your org and inspected in its
reference. Follow each returned nextRecordsUrl while done=false, staying on the
approved instance. Do not manufacture a query locator or infer that one response
contains the full dataset. Respect the org's API request budget.

Classify responses by the specific resource and pinned version. The current
Salesforce upsert reference describes201 for creation and, in API46.0+,200 with
a response for an existing match; older versions used204 for that case. A300
response means multiple external-ID matches: stop and resolve uniqueness.
401 -> authorized refresh/re-authentication, bounded retry;403 -> inspect the
errorCode (permission denial differs from REQUEST_LIMIT_EXCEEDED);400 -> fix
payload/schema rather than repeat unchanged; timeout or lost response -> query
the external identity before retrying an uncertain create. Never log bearer
tokens, complete request bodies or customer data in a public transcript.

NOTES AND RECOVERY
Send only minimal identifiers in a VICIdial Call URL. Notes belong in a protected
request body sent by the relay after authorized lookup and field-policy review.
An identifier can still be personal data when linked; minimize and restrict logs.
No browser gets Salesforce client secrets or a broad dialer API password.

Pause the worker and affected integration field to stop new work; preserve the
receipt/outbox/identity/checkpoint ledgers. Do not undo good historical events
or delete mappings merely to make counts agree. Recover by reconciling the
pending identities and resuming from a reviewed checkpoint. A local receipt
acknowledgement is not a Salesforce write acknowledgement.

Primary references:
https://www.vicidial.org/docs/CALL_URL_FEATURES.txt
https://www.vicidial.org/docs/NON-AGENT_API.txt
https://developer.salesforce.com/docs/platform/api-rest/guide/resources-query.html
https://developer.salesforce.com/docs/platform/api-rest/guide/dome-upsert.html
https://developer.salesforce.com/docs/platform/api-rest/guide/errorcodes.html
