When you make looping animations, especially animations whose entire motion is procedural, you want to make sure that the first and last frames have the same keys, but also that the Handle Type for those keys is set to Vector. You can change these in the Curves window.
DO NOT TOUCH the vector handles;
Assuming that all handle types are Automatic and you did not adjust the bezier handles, when you convert them to Vector, they should already be flowing the same direction. (The tangents should be the same). If they are not (look at them, compare), you can manually adjust the vector handles or re-key the first and/or last keyframes.
Example of when to expect good results automatically:
A bobbing motion where cardinal (X,Y, and/or Z) position(s) is/are keyed. Suppose you key only one period. You will want 5 keys for the 4 distinguishable segments:
x x x
the default interpolation ("Automatic") will create smooth bezier curves that work great in the middle but flatten out at the ends. Assuming this motion has its keys equally spaced and the average position is keyed, if you now select the first and last key and change the handle type to "Vector", their tangents will match and the motion will be seamless.
Also: Remember that the last frame needs to be excluded (since it is literally a copy of the first frame (yes, I see you do). This is done by setting the last frame value in the Timeline window to 1-less-than the frame the last key is on.