← Blog
Jascha Kaykas-Wolff··6 min read

AI SDR CRM Writeback: HubSpot, Salesforce, and the Write That Fails

The four records an outbound agent should write back to your CRM, how to key them so a retry never makes a duplicate, and what happens on the day the CRM refuses one.

The meeting booked fine. The write did not.

A prospect replies on a Tuesday afternoon, the agent offers two times, and a slot lands on the AE's Google Calendar for Thursday at ten. Then the agent tries to create the lead in Salesforce, and a validation rule somebody added last spring rejects it because Lead Source is blank. The agent logs the error to a file nobody reads. On Thursday at 9:55 the AE searches Salesforce for the prospect's name, finds nothing, and starts the call with "so, remind me how we got connected?"

The pages that rank for AI SDR CRM writeback are long (the three we read run roughly 2,800 to 3,800 words) and they agree on a lot. Use a native API connection rather than a chain of webhooks. Map fields deliberately, with "update if blank" rules for anything a human already filled in. Sync in both directions, because writeback without reading the rep's changes is half an integration. One of them gets properly into how differently the two APIs behave. We agree with all of it.

None of them say what the agent should do when the write fails. That gap is what this page is about. Our AI SDR CRM integration guide already covers when a cold prospect deserves a CRM record and which fields an agent must never touch, so this one starts at the moment the agent actually calls the API.

Four writes worth making

Most of what an agent could write back is noise. These four are what a rep opens.

The person, on first reply

HubSpot contact · Salesforce lead or contact

In HubSpot this is a contact. In Salesforce, decide up front: a reply from someone at an account you already have becomes a contact on that account, and a reply from an unknown company becomes a lead. Agents left to choose will pick differently on Tuesday than they did on Monday.

The conversation

HubSpot email engagement · Salesforce task

Every email the sequence sent to that person plus the reply itself, with the source URL the first email leaned on attached to step one. One activity per message, each carrying the sequence step, so the timeline reads in order.

The opt-out

Do-not-contact property on both

The one write that can never wait for a human or a nightly job. If the CRM rejects it, the agent keeps retrying and the local suppression list blocks the address in the meantime.

The booked meeting

HubSpot meeting · Salesforce event

Time, attendee, the calendar link from Calendly or Google Calendar, and a pointer back to the reply that produced it. The AE opens this one five minutes before the call, so it has to be complete.

Everything else stays in the agent's own records: the five to eight touches across email and LinkedIn that got no answer, and the research it did on people who never wrote back. Our AI SDR audit log keeps all of that, and the CRM only receives what a person in sales will act on.

HubSpot and Salesforce want different things

Almost nothing transfers between them.

HubSpot keeps one person object and lets lifecycle stage carry the meaning. Salesforce splits people into leads and contacts, and many orgs have years of conversion habits built on that split, so an agent that creates contacts directly can quietly skip the lead assignment rules your ops team depends on. Custom fields in Salesforce end in __c and live behind field-level security, which means the integration user can be allowed to read a field and still get an error writing it. HubSpot is looser about properties and stricter about timing: a contact created a moment ago may not come back from search yet, and an agent that searches, finds nothing, and creates again will make the duplicate itself.

Read the validation rules in your Salesforce org before the first write, all of them, including the ones from an admin who left in 2023.

Lifecycle stage

HubSpot will not move lifecycle stage backward through an ordinary update, so an agent that marks someone an opportunity off an optimistic reading of "sounds interesting, send me more" has made a mistake a person has to clear by hand.

Give every write a key

Retries are where duplicates come from. The agent sends the create request, the API takes eleven seconds, the tool times out, and the agent tries again, not knowing the first one landed.

Every record the agent writes should carry an ID from the agent's side, the same one in its audit log. In Salesforce, put it in a custom field marked as an External ID and write with upsert on that field, so the second attempt updates the record the first attempt made. In HubSpot, create a custom property that requires unique values and look up by it before creating. Activities get the same treatment: the key for a logged email is the prospect plus the sequence step, so step three can only ever appear once on the timeline.

When the CRM says no

Failures come in two kinds, and the agent has to tell them apart.

The CRM was unavailable, usually a timeout or a rate limit. Those get retried with the same key, and while the write is pending the agent sends nothing further to that prospect. We hold the next touch because a follow-up sent while the reply record is missing is exactly how a rep ends up emailing someone the agent already booked.

The CRM refused: a validation rule, a required field, a permission the integration user lacks, a duplicate rule that fired. Retrying those changes nothing. The agent stops the sequence for that person, posts the exact error and the full payload to Slack, and a human fixes the record or the rule. If the refused write belongs to a booked meeting, the Slack card goes to the AE who owns the slot, with the reply text pasted in, because that person needs the context before the call whether or not Salesforce ever gets it.

Opt-outs break both rules. They retry forever and they never wait, and the local suppression list blocks the address from the first second, the same way our AI SDR kill switch treats a failed check as a stop.

An expired OAuth token looks like the first kind and behaves like the second. It never fixes itself, so it gets its own alert.

Reconcile every night

Once a night, compare the agent's log against the CRM: each of the four writes above from the last 24 hours should have a matching record carrying the agent's ID. Anything missing goes on a short list for the morning. On a healthy day that list is empty, and an empty list for a week is the only evidence we trust that writeback works, more than any green status light on an integration settings page.

Why we care

After the free pilot we get paid per qualified meeting, and a qualified meeting is one where the prospect shows up. A prospect who gets asked how they got connected, on a call they took because of a specific email, has a reason to show up less engaged next time, or not at all. Writeback is the piece of the system that decides whether the AE walks in with the email that earned the reply or walks in cold.

Mira runs 24/7 on OpenClaw from a Mac mini in San Francisco. The OpenClaw MCP Integration Kit ($9.99) ships twelve annotated MCP skill configs, HubSpot and Slack among them, with a tool permission matrix and an auth troubleshooting runbook. For which tools an agent may call without a human click, read our MCP tool permission matrix for outbound, or see how Mira works.