A bulk operation was run on the wrong segment. Tags are gone, so are the links between contacts and segments, sometimes the records themselves. There is no undo button in the interface, support often takes a day to reply, and the managers cannot work in the meantime.
In most cases the data has not gone anywhere.
#Deleted, or only marked as deleted
Before doing anything, answer one question: is the record deleted, or marked as deleted?
Soft delete — the row stays in the database, it simply gets a flag on it. Plenty of CRMs work this way, because it is cheaper and safer. Checking is easy: request the object by its id through the API. If a 200 comes back and the data is there, it is a soft delete, and recovery comes down to clearing the flag or recreating the link.
Hard delete — the row is gone. Then your only source is a backup or an export made before the incident.
#Where to get the list of what to restore
You need a list of pairs — what was linked to what — as it stood before the incident. Sources, most reliable first:
- a database backup — if you have one and it was made before the event;
- an export from the admin panel — many systems will let you download the links as a table;
- logs from the operation itself — if whoever deleted the data kept the output of the run;
- other systems — if the same data is duplicated in another service.
There is less time here than it looks: in some systems, records marked as deleted are physically removed after a few days. So the list comes first, before you write any recovery code.
#Why the dry run is mandatory
By default the recovery script has to do nothing. Only show what it is about to do.
node restore.js # sends nothing, prints the first 10 requests
node restore.js --live # only after you have checked that by eyeThe dry run checks three things: the ids are right, the method is right, and the count is right. If the script is about to make thirty thousand requests and three thousand links were deleted, something is wrong with the list, and it is better to see that now.
#Why every request goes into a log
This is the main part, and it is done before the run, not after.
Every request that goes out gets its own line: method, address, body, response code, time. The format is one JSON record per line, so the file can be read in pieces instead of held in memory.
That log gives you three things:
- proof. You can see exactly what was done, rather than “we think we restored it”;
- recovery after a failure. The connection dropped halfway — a rerun picks up only what is not in the log file;
- undo. The same file, run back through with the opposite method, puts everything the way it was.
node restore.js --live --method=DELETE --from-log=logs/2026-08-13.jsonlThat is the undo button the interface does not have. You have to build it yourself, and build it before the live run.
#What to check before the live run
- Whatever was deleting has been stopped.
- The list is collected and saved as a file of its own.
- The dry run showed the expected count and the right method.
- It has been tried on one record, and the result has been looked over by eye in the interface.
- The script writes its log to a file, not to the console.
- You know how to roll it back: the rollback command is written in advance.
The single-record item is the one people skip most often. It costs a minute and shows you the mistake before it becomes a bulk one.
#What to do after the recovery
An incident is closed by removing the cause, not by the recovery.
In some CRMs bulk operations are open to everyone with access to the segments. The minimum that makes sense: narrow down who is allowed to run them, and set a rule that an export of the segment is saved before any bulk action. Those thirty seconds turn the next recovery into a single import.
#Takeaways
- Stop whatever is deleting first, and only then restore.
- Check whether it is a soft delete: the data is often still there.
- Put the list together straight away — flagged records can be removed for good.
- By default the script writes nothing; the live run sits behind a flag of its own.
- Every request goes into the log. That same log is the proof, the way to carry on after a failure, and the rollback.
- Before the bulk run, try it on one record.
#Common questions
#How much time do you have to recover?
It depends on the system. Records marked as deleted can be removed for good after a few days. Assume you have twenty-four hours, and put the list together first.
#Can you recover with no backup?
Often yes — if it is a soft delete, or if the same links exist in another system. If it is a hard delete and nothing is duplicated anywhere, there is nothing to restore from.
#Who should do this — your team or the service’s support?
If there is an API, it is faster to do it yourself: support often takes a day to answer and rarely restores selectively. It is worth going to them when it is a hard delete and you need a copy from their side.