this is the only way I know how to do this programmatically. from my understanding, keyframes for individual nodes are handled at the node tree level.
first, you have to find your node tree:
bpy.data.node_groups
contains them all, find which element of this list is the node tree in question, for example:
node_tree = bpy.data.node_groups['GeometryNodes']
Then, there is something tricky about this step. You can access the keyframe data using:
node_tree.animation_data
BUT, it will be None unless there are existing keyframes. Easy way around this is to just quickly manually add a keyframe to your node (there has to be a way to do this step in Python). Then, when you call node_tree.animation_data
it will not be None.
Then, you can view the keyframe fcurves like so:
node_tree.animation_data.action.fcurves
this is also a list, there must be a better way of doing this, but you can iterate through each one and look at it's data_path to determine if it belong to the node in question:
node_tree.animation_data.action.fcurves[0].data_path
you can then edit your dummy keyframe value like this:
node_tree.animation_data.action.fcurves[0].keyframe_points[0].co = (frame, value)
you can also add new keyframe_points and edit them using the same approach, but first calling
node_tree.animation_data.action.fcurves[0].keyframe_points.add(npoints)
to add them first.
doing this approach, you can add and edit as many keyframes as you want and they will be reflected in the node.
Hope it helps.