Here's how I did it in a recent project:
$fileIds = array();
// get remote image and store in temp path
$imageInfo = pathinfo($data['image_url']);
$tempPath = CRAFT_STORAGE_PATH . 'runtime/temp/' . $imageInfo['basename'];
file_put_contents($tempPath, fopen($data['image_url'], 'r'));
// insert the file into assets
$response = craft()->assets->insertFileByLocalPath(
$tempPath,
$imageInfo['basename'],
$myAssetFolderId, // notice, this is the id of the folder you want to upload to
AssetConflictResolution::KeepBoth
);
// if the response is a success, get the file id
if ($response && $response->isSuccess()) {
$fileIds[] = $response->getDataItem('fileId');
}
// create a new entry
$entry = new EntryModel();
$entry->sectionId = $mySectionId;
$entry->typeId = $myEntryTypeId;
$entry->authorId = 1;
// set your content, including image field by id
$entry->getContent()->title = $data['title'];
$entry->getContent()->mainImage = $fileIds;
$success = craft()->entries->saveEntry($entry);
I included the entry saving part of it to show how the response is used to get the file id(s) and so on.
Whether this is the "correct" way to do it or not, I don't know. :)