Like rating summaries, custom options are stored separately to the product object. The best way to set them is to first create an array with the data for the option:

$options = array();
$options[$sku] = array(
 'title' => 'Option Title',
 'type' => 'radio',
 'is_require' => 1,
 'sort_order' => 0,
 'values' => array()
);
$options[$sku]['values'][] = array(
 'title' => 'Option Value 1',
 'price' => 0.00,
 'price_type' => 'fixed',
 'sku' => '',
 'sort_order' => '1'
);
$options[$sku]['values'][] = array(
 'title' => 'Option Value 2',
 'price' => 89.00,
 'price_type' => 'fixed',
 'sku' => '',
 'sort_order' => '1'
);

Note that the $options array has been created in this way to allow for multiple products to be filled out at once. Simply change values for more SKUs. This array can be filled out however is most appropriate for your system. This could be from an XML-RPC connection to another service, dynamically calculated values, or read from a CSV file. The sample values used in the above example should map logically to the values presented in the Magento product editor interface.

Once the array of data is set up, the custom options can be added to a product like so:

foreach($options as $sku => $option) {
 $id = Mage::getModel('catalog/product')->getIdBySku($sku);
 $product = Mage::getModel('catalog/product')->load($id);
 
 if(!$product->getOptionsReadonly()) {
 $product->setProductOptions(array($option));
 $product->setCanSaveCustomOptions(true);
 $product->save();
 }
}

Using the above code you can add custom options to all the products defined in the array that was set up previously. With slight modifications, it can be used to pull values from other sources. If your catalogue includes a lot of products that require custom options then having a script to set these values automatically can save a great deal of time.