I would start writing a generic combinations function which generates combinations of a specified size -
def combinations(items, size):
  if size == 0:
    yield ()
  elif not items:
    return
  else:
    head, *tail = items
    for p in combinations(tail, size - 1):
      yield (head, *p)
    yield from combinations(tail, size)
We're relying on Python's generators which lazily produce the output. We can use list to get all of the results -
data = [ 1, 2, 3, 4, 5, 6, 7, 8 ]
list(combinations(data, 2))
# [ (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 3),
#   (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (3, 4), (3, 5), (3, 6),
#   (3, 7), (3, 8), (4, 5), (4, 6), (4, 7), (4, 8), (5, 6), (5, 7),
#   (5, 8), (6, 7), (6, 8), (7, 8) ]
It can easily generate combinations of other sizes, and the input iterable can contain elements of any type -
list(combinations("abcd", 3)))
# [ ('a', 'b', 'c'), ('a', 'b', 'd'),
#   ('a', 'c', 'd'), ('b', 'c', 'd') ]
By writing combinations as a standalone function we detangle the concerns of our program. As a result sum_pairs is easy to write and test. We pass 2 as the size argument because we want to generate pairs (of two numbers) -
def sum_pairs(ints, goal):
  for p in combinations(ints, 2): # <-- use combinations
    if sum(p) == goal:
      return p
  return None                     # <-- don't forget unsolvable case
print(sum_pairs(data, 13))
# (5, 8)
Because we are using Python's generators, sum_pairs will return immediately after finding an answer. This short-circuit behaviour means no unnecessary combinations or iterations are wasted.
When given an unreachable goal, sum_pairs will return None -
print(sum_pairs(data, 99))
# None
A small modification demonstrates the effectiveness of our combinations generic. In this program, any_sum will find a combination of any size that sums to our expected goal -
def any_sum(ints, goal):
  for size in range(len(ints)):
    for p in combinations(ints, size + 1):
      if sum(p) == goal:
        return p
  return None
While this is not the most efficient implementation of any_sum, it does show how combinations can be reused without introducing new complexity -
print(any_sum(data, 17))
# (2, 7, 8)
print(any_sum(data, 25))
# (4, 6, 7, 8)
print(any_sum(data, 33))
# (3, 4, 5, 6, 7, 8)
print(any_sum(data, 99))
# None