한니발은 이탈리아에서의 놀라운 전과에도 불구하고 로마의 동맹국들의 봉기를 이끌어내지 못했다. 급기야 지원군으로 오던 동생 하스드루발 바르카도 메타우로 전투에서 죽고 전선은 교착상태에 빠졌다. 또 다른 동생 마고네도 부상을 입고 제노바에서 꼼짝 못하고 있는 상황이었다.
로마의 스키피오 아프리카누스는 이베리아반도에서의 승리에 이어 북아프리카에 교두보를 확보하였으나 신중을 기하는 원로원의 반대로 카르타고에 대한 적극적인 공세를 취하지 못하고 있었다. 그러나 마시니사와 함께 서부 누미디아의 시팍스를 물리치고 기병을 획득하자 스키피오는 자신감을 얻고 공세에 나섰다.
그사이 양쪽은 강화를 위해 협상이 오고 가고 있었다. 로마는 아프리카 이외의 모든 영토의 포기, 5천 탈란트의 전쟁 배상금, 그리고 카르타고 해군의 해체를 조건으로 내세웠다. 한니발과 마고네는 카르타고 본국에서 송환명령이 떨어져 역전의 용사 1만2천 명을 이끌고 아프리카로 돌아왔다(마고네는 돌아오는 항해중에 사망했다.). 그러나 카르타고는 갑자기 강경론이 우세해지고 협상을 결렬시켰다.
이제 스키피오와 한니발은 각각 국가의 운명을 걸고 북아프리카에서 결전을 벌일 수밖에 없었다. 기록에 따르면 전투 전날 두 사람은 단독으로 대면했다고 한다. 이 단독 회담에서 한니발은 이탈리아에서 자신의 일을 상기시키면서 운명은 알 수 없는 것이니 위험한 도박을 피하고 여기서 그만두자고 말했다. 그러나 스키피오는 로마의 강화조건을 거듭 주장하며 여기서 멈출 수는 없다고 말하여 결전을 피할 수가 없었다.
전투 상황
포진
자마 전투에서 로마군과 카르타고군은 통상적인 포에니 전쟁 전투와 정반대의 상황에 있었다. 항상 로마군은 보병이 많았고 기병이 부족했으나 이번에는 누미디아 기병이 로마군으로 넘어간 탓으로 카르타고군이 기병이 상대적으로 부족했고 대신에 카르타고군이 보병이 더 많았다.
카르타고군은 80마리의 전투 코끼리를 선두에 배치하고 두 번째 열에 비교적 전력이 약한 용병 혼성군을 세 번째 열에 카르타고 시민병을 배치했다. 후방으로 200보 떨어진 곳에 한니발 자신과 이탈리아에서 데려온 최정예 부대를 배치했다.
이에 맞서는 로마군은 보통의 진영의 소대간벽보다 더 넓게 진영을 짜고 경무장 보병도 소대를 편성하였고 보병은 스키피오 자신이 지휘하고 양쪽 날개에는 마시니사가 이끄는 누미디아 기병과 로마 기병을 각각 배치하였다.
전개
한니발이 보병의 질적 열세를 극복하기 위해 준비한 80마리의 전투 코끼리가 먼저 로마군 진영으로 돌진했다. 그러나 코끼리에 대비해 평소보다 넓게 소대간격을 벌이고 경무장 보병도 소대단위로 편성한 스키피오의 능숙한 대처로 인해 별 효과를 거두지 못했다. 로마군은 누미디아 기병의 보강으로 숫적으로 우세해서 카르타고 기병을 밀어냈다. 로마 보병은 전진을 시작했고 혼성군과 시민병의 대열을 물리쳤다. 카르타고군은 등을 돌려 달아나려 했으나 네 번째 대열에서 뒤섞이는 것을 허락치 않았기에 좌우로 흩어져 달아났다.
종반
한니발은 로마군이 지쳐 있다고 판단, 자신의 정예보병을 전진시켰다. 스키피오는 한니발의 정예군이 다가오는 것을 보고 지친 하스타티를 좌우로 산개하고 프렌키페스와 트리아리를 합쳐 전면에 내세웠다. 치열한 전투 중 적을 추격하던 로마의 기병이 돌아와 뒤를 찌르자 한니발의 군대는 무너졌다.
결과
이 전투에서 카르타고군의 피해는 전사자, 포로 모두 합해 4만 명이었고, 로마군은 최소1500에서 최대4000여 명이었다. 이 전투로 16년을 끌어온 제2차 포에니 전쟁은 종결을 맞는다. 카르타고 의회는 로마가 제시한 강화조건을 승인하고 전쟁을 종결시켰다. 이후로 로마의 징벌적 휴전조항에 의해 카르타고는 다시는 지중해에서 군사강국이 되지 못했다. 약 70년후 제3차 포에니 전쟁이 발발하지만 그때도 카르타고는 자신의 영토를 간신히 지킬만한 군사력만 가질 뿐이었다.
결국 이 전투의 영향으로 인하여 카르타고는 쇄락과 멸망의 길로 가게 된다.