משקרב החורף של אותה שנה התקרב חניבעל לנולה אולם מצא את העיר מוכנה היטב למצור. הוא ידע שמחסור באספקה והחורף המתקרב לא יאפשרו לו להטיל מצור יעיל על העיר, על כן נסוג וחיפש מקום לחייליו לחורף. העיר העשירה קפואה פתחה בפניו את שעריה וחניבעל נפגש עם נכבדי העיר. חניבעל הורה לחייליו לשלם בכסף מלא על משתאות מזון או כלי נשק אף על פי שצבאו החזיק למעשה בעיר. הוא קיבל שם נציגים משבטים שונים ביניהם הברוטים, הלוקנים, הסאמניטים והאפולים שכולם הציעו לו נאמנות. בסוף נובמבר או בתחילת דצמבר של שנת 216 לפנה"ס, כבש חניבעל לאחר קרב קאסילינום את העיר קאסילינום.
ממקום מושבו בקפואה הבין חניבעל שעליו להיעזר בבן ברית חזק כדי לנצח במלחמה. קרתגו נמנעה מלשלוח לו כוחות נוספים ושליט אחר היה יכול לעשות זאת. אותו זמן השליט החזק ביותר ביוון היה פיליפוס החמישי מלך מוקדון, שהיה שקוע במלחמה נגד האיטולים, אולם לאחר קרבות טראסימנוס וקאנאי החליט כי יכולה לצמוח לו תועלת ממלחמה משותפת נגד רומא. בעקבות המלחמה האילירית השנייה, החזיקו הרומאים באותה העת במספר ערים אסטרטגיות באיליריה וערערו את שליטתו של פיליפוס בבלקן. על כן חתם על הסכם שלום עם האיטולים והחל ליצור מגעים עם חניבעל. פוליביוס מביא את נוסח החוזה בין חניבעל לפיליפוס לפיו: "אתם תסייעו לנו לפי הצורך ולפי התיאומים שנעשה בינינו, ולאחר שהאלים יעניקו לנו את הניצחון על הרומאים ובעלי בריתם..." קרתגו תקבל חזרה את סרדיניה, קורסיקה וסיציליה, על רומא ייאסר לפתוח במלחמה על מוקדון או על קרתגו, והרומאים יוותרו על קרקירה, אפולוניה, אפידמנוס, פארוס, דימאלי, ואזורים נוספים, ויעניקו אותם למוקדון. כמו כן ישוחררו כל ידידי דמטריוס מפארוס, ידידו של פיליפוס, שהיו כלואים ברומא. הברית נכנסה לתוקפה כבר בקיץ של שנת 215 לפנה"ס, אולם למעשה בשל פעולות נמרצות מצד הצי הרומאי פיליפוס לא סייע רבות לחניבעל.
הרומאים מצידם השתדלו כל העת לפגוע בערים שכרתו ברית עם חניבעל, ובשנת 214 לפנה"ס הטילו מצור על קפואה. חניבעל שלא רצה לאבד את העיר שסיפקה לו אספקה וציוד, עשה מאמצים נואשים להציל אותה. במסגרת מאמצים אלו אף העמיד פנים שהוא מטיל מצור על רומא, כדי להכריח את הרומאים לפנות כוחות מקפואה. אולם הרומאים לא הלכו שולל וחניבעל נאלץ לסגת. בשנת 211 לפנה"ס נפלה קפואה. שנה לאחר מכן חזר מסיציליה המצביא הרומאי מרקוס קלאודיוס מרקלוס, שהשלים את כיבושה של סירקוסאי, הגדולה והעשירה שבערי סיציליה, שעברה גם היא לצד הקרתגי לאחר קרב קאנאי. מרקלוס היה מוכשר בהרבה ממרבית המצביאים הרומאים שנגדם לחם חניבעל עד אז. הוא כונה בפי הרומאים "חרבה של רומא", וכשרונותיו בקרבות ובמצור הפכו אותו לאויב משמעותי.
חניבעל נאבק בו ובמצביאים רומאים נוספים מספר שנים, כשהוא מאבד את מאחזיו וחייליו. עם תחילת שנת 209 לפנה"ס ספג חניבעל מכה קשה כאשר פאביוס מאקסימוס כבש את העיר טראנטום בעזרת בגידה מבפנים. טראנטום הייתה עיר נמל יוונית שהשליטה בה הייתה חשובה מאוד לחניבעל, משום שהיא שכנה בנקודה אסטרטגית ואפשרה לו גישה לים, וכן ראש גשר לתגבורת מקדונית מן המזרח. ערים נוספות דוגמת סלאפיה נכבשו גם הן, והברית שבנה חניבעל החלה להתפורר. כקונסולים של שנת 208 לפנה"ס נבחרו מרקלוס (פעם חמישית ואחרונה בחייו) וטיבריוס קווינטיוס קריספינוס. זה האחרון הטיל מצור על לוקרי (לוצ'רה המודרנית), אולם חניבעל הניס אותו משם. קריספינוס התאחד עם צבאו של מרקלוס, אולם חניבעל ארב להם בוונוסיה, ובמהלך הקרב מרקלוס נהרג ועמיתו נפצע קשה.
חניבעל לקח כשלל את החותמת של מרקלוס, וניסה לנצל אותה כדי לכבוש את סלאפיה. הוא כתב איגרת בה הורה על החלפת חיל המצב הרומאי בעיר, וחתם עליה בשם מרקלוס. הוא הלביש קבוצת לוחמים דוברי לטינית במדי הצבא הרומאי, ושלח אותם לעיר. אולם קריספינוס הזהיר מראש את מפקדי חילות המצב שמרקלוס מת. מפקד חיל המצב של סלאפיה נתן לחיילי חניבעל להיכנס לעיר ולאחר מכן טבח בהם.
חניבעל הבין שכוחות רעננים הם הסיכוי היחיד שלו לנצח, ובאמצעות עיר הנמל האחרונה שלו קרוטון, יצר קשר עם אחיו עזרובעל שלחם ברומאים בהיספניה, וביקש ממנו לנסות להגיע לאיטליה באותו מסלול שבו הגיע הוא עצמו. עזרובעל הצליח לחמוק מהרומאים לצפון היספניה, ופתח במסע מזורז במסלול של אחיו. הוא חצה את הפירנאים, ונותר בגאליה למשך החורף כדי לגייס חיילים חדשים. לאחר מכן במהלך האביב חצה במסע מזורז את האלפים. מסעו היה קל בהרבה מזה של אחיו, כיוון שהוא התנהל במזג אוויר נוח יותר עם מורי דרך מנוסים, והשבטים הגאלים שיתפו פעולה במידה רבה יותר. עזרובעל הגיע אל עמק הפו בקיץ של שנת 207 לפנה"ס עם 30,000 אנשים בערך, ואילו היה מצליח להתחבר לכוח של אחיו ככל הנראה היה מצבו של חניבעל משתפר לאין שיעור. כקונסולים של אותה שנה כיהנו גאיוס קלאודיוס נרו ומרקוס ליוויוס סלינטור. נרו נאבק בחניבעל, וסלינטור המתין לעזרובעל. זה האחרון שלח שליח לאחיו כדי להודיע לו על בואו ולתאם את מקום המפגש, אך השליח נתפס בדרך לחניבעל בידי אנשיו של נרו. נרו ידע היטב שאם עזרובעל יחמוק מסלינטור ויחבור לחניבעל יקיץ הקץ על רומא, לפיכך החליט להפר את הוראות הסנאט שהורה לו לא לעזוב את לוקאניה, ויצא אל סלינטור החונה במטאורוס.
נרו חמק מחניבעל, והצעיד את חייליו במהירות כמה עשרות קילומטרים, עד שלפנות בוקר הגיע אל סלינטור והזהיר אותו. השניים הסתירו את בואו של נרו והעמידו פנים שיש במחנה רק קונסול אחד, וכך מצא עצמו עזרובעל בנחיתות מספרית בקרב מטאורוס. עזרובעל נהרג בקרב וצבאו הובס והתפזר. לאחר הקרב ראשו נערף, הושם בשק, והושלך אל מחנהו של חניבעל. שני שבויים אפריקאים שוחררו כדי לספר לחניבעל על הקרב. ליוויוס מספר שכאשר חניבעל ראה את ראשו של אחיו, הוא הכריז שקרתגו הפסידה כעת במלחמה.
חזרה לאפריקה.
לאחר שהשלים את כיבוש היספניה, נערך המצביא הרומאי סקיפיו אפריקנוס בסיציליה (בנו של סקיפיו שהובס על ידיד חניבעל בקרב טיקינוס) לקראת פלישה לאפריקה, במטרה להסיט את תשומת הלב של חניבעל מאיטליה אל מולדתו. בשנת 204 לפנה"ס נחת סקיפיו על החוף האפריקאי והטיל מצור על אוטיקה. מולו נערך המצביא הקרתגי עזרובעל בן גיסקו, ולצידו סיפאקס הנומידי.
סקיפיו הבין שיתרון הקרתגים נובע מחיל הפרשים המעולה שלהם, והחליט לנצל את הסכסוכים הפנימיים בנומידיה כדי להשיג גם לעצמו חיל פרשים כזה. המנהיגים החזקים ביותר בקרב הנומידים באותה תקופה היו מסיניסה מלך נומידיה המזרחית, וסיפאקס מלך נומידיה המערבית. הקרתגים זלזלו במסיניסה הצעיר והעדיפו את סיפאקס על פניו. סיפאקס היה נשוי לאשה קרתגית בשם סופוניסבה, שגם מסיניסה חיזר אחריה בזמנו. סופוניסבה גרמה לכך שסיפאקס שירת בנאמנות את הקרתגים, בעוד מסיניסה הנעלב חבר לסקיפיו.
בהתקפת פתע הצליח סקיפיו להצית את המחנות הקרתגיים ולהביס את צבאותיהם. מסיניסה פלש לממלכתו של סיפאקס יחד עם הלגאט הרומי גאיוס ליליוס, והשניים הביסו את צבאו בקרב קירטה וכבשו את ממלכתו. סיפאקס נלקח בשבי לרומא, וסופוניסבה אשתו התאבדה בבליעת רעל. במועצת הזקנים של קרתגו עלתה ההצעה להחזיר מאיטליה את חניבעל ומאגו (שניהל מערכה עם הרומאים בעמק הפו), אולם מתנגדיהם הפוליטיים בראשות חנו הגדול התנגדו להצעה. התנגדותם התבררה כהרת אסון, לאחר שהמצביאים הקרתגים עזרובעל וחנו בן בומילקר, הובסו בידי סקיפיו ומסיניסה בקרב המישורים הגדולים. בלית ברירה החלו הקרתגים במשא ומתן עם הרומאים, אך בד בבד קראו לחניבעל לשוב לאפריקה.
בחודש יולי של שנת 203 לפנה"ס עזב חניבעל במפתיע את איטליה; הוא חמק ממנה בעזרת צי שיצא מקרוטון בלי שהרומאים הרגישו בכך, והפליג עם צבאו שכלל כעת בעיקר גאלים וברוטים אל אפריקה. לא ברור מה היה גודל הצבא שחניבעל חזר עמו, חסידיו של סקיפיו טוענים שמספרם הגיע ל-24,000, בעוד חסידי חניבעל מצמצמים את המספר לכדי 10,000. כאשר חניבעל הגיע כבר היה חורף, ולפיכך דחו שני הצדדים את פעולות האיבה. עם בוא האביב של שנת 202 לפנה"ס הפרו הקרתגים את ההסכם, ובזזו ספינות אספקה רומאיות. בתחילת הקיץ ארגן סקיפיו פעולת תגמול גדולה, וצעד במהירות לכיוון הדרומטום שם חנה חניבעל, כשהוא בוזז בדרכו את האזורים הכפריים של קרתגו. חניבעל התקדם גם הוא במהירות כדי לפגוש את סקיפיו, שני הצדדים נפגשו בסוף בעיר "זאמה הקטנה" הידועה יותר בשם זאמה רגיה (Zama Regia), עיר בקרתגו על גבול נומידיה.
קרב זאמה וסיום המלחמה.
חניבעל וסקיפיו ניסו בתחילה לפתור את העניין בדרכי שלום, וערכו מפגש בזאמה. ליוויוס מתאר בהרחבה את המפגש ההיסטורי ביניהם, ומתאר בהרחבה את נאומיו המתרפסים של חניבעל. ככל הנראה ישנה הגזמה רבה בתיאורים אילו. סקיפיו דרש את החזרת כל שבויי המלחמה והעריקים הרומאים, הכרה בשליטה הרומאית בהיספניה, סיציליה, סרדיניה, קורסיקה, והאיים הבליארים, והכרה במסיניסה כמלך נומידיה כולה. כמו כן דרשו הרומאים את הסגרת כל הצי המלחמתי הקרתגי, וצמצומו לכדי 20 ספינות בלבד. על קרתגו ייאסר לפתוח במלחמה על רומא, והיא תשלם קנס של 5,000 טלנטים. תנאים אלו היו סבירים ולא היו אמורים למוטט יותר מדי את כלכלת קרתגו, אולם חניבעל הסכים לכל התנאים פרט לפירוק הצי והסגרת העריקים. הדבר שם קץ למשא ומתן, כיוון שמלכתחילה הסכים סקיפיו לשלום רק אם חניבעל יציע יותר, והוא הציע פחות.