The tourists responded superbly to their thumping 125-run defeat in the series opener at Bloemfontein, Mohammad Irfan taking four for 33 to reduce the Proteas to 62 for five.
Farhaan Berhardien's half-century led a fightback but the hosts returned after an interruption by heavy rain to lose their last three wickets cheaply.
Graeme Smith and Hashim Amla had put on 22 in the opening four overs before Amla followed a wider one and edged Irfan behind for 17 and then new man Colin Ingram was dismissed by the very next delivery. He too nicked to Kamran Akmal, but there was some uncertainty on the field leaving the decision to be confirmed on review.
AB de Villers stroked his fourth ball to the extra-cover ropes but became Irfan's next victim immediately afterwards, Younis Khan holding on in the slips.
That left the score at 35 for three and that became 43 for four in the eighth over as Junaid Khan got in on the act, Smith caught behind for 10 from a mistimed pull.
South Africa were not short of boundaries, but kept losing key men. The 11th over was a case in point, with 10 runs coming before Irfan sent Faf du Plessis back with the last delivery. His 17 was lively, but ended when the giant Irfan got down well to pouch a caught and bowled chance.
Berhardien and Ryan McLaren rescued the innings from meltdown, putting on 44 for the sixth wicket at an impressive rate but McLaren eventually perished, the third man out for 17, when Mohammad Hafeez pinned him lbw.
Robin Peterson proved an even better foil for Berhardien, who passed 50 for the first time in internationals from 60 balls with a dashed a two off Shahid Afridi. Hafeez removed him just before the rain came, his 58 containing five fours, with Peterson still in place on 39no.
Kyle Abbott was immediately dismissed for five after the rain delay and Junaid Khan speared one through Dale Steyn's defences, before Peterson slashed Saeed Ajmal straight up in the air to be caught by Nasir Jamshed for 44.