I figured it out.
The documentation here: https://www.paypalobjects.com/webstatic/en_US/developer/docs/pdf/pp_payflowpro_guide.pdf
on page 40 mentions it briefly, but doesn't go into much detail about this checkout flow even though it seems pretty common.
My assumption was right, in that I could just do an address verification request first with all the CC info, and use the PNREF returned. I save the PNREF id in my session and reuse it to submit a request that looks like this:
def authorize_transaction(pnref)
make_request(authorization_data(pnref))
end
def authorization_data(pnref)
{
"TRXTYPE" => "A",
"TENDER" => "C",
"USER" => PAYPAL_API["user"],
"PWD" => PAYPAL_API["pwd"],
"VENDOR" => PAYPAL_API["user"],
"PARTNER" => "Paypal",
"AMT" => purchase.total_price,
"ORIGID" => pnref,
"VERBOSITY" => "HIGH"
}
end
And receive the desired response:
{"RESULT"=>"0", "PNREF"=>"A10A6A9C08E1", "RESPMSG"=>"Approved", "AUTHCODE"=>"752PNI", "AVSADDR"=>"Y", "AVSZIP"=>"Y", "HOSTCODE"=>"A", "PROCAVS"=>"Y", "VISACARDLEVEL"=>"12", "TRANSTIME"=>"2014-01-31 11:53:56", "FIRSTNAME"=>"net", "LASTNAME"=>"theory", "AMT"=>"15.64", "ACCT"=>"1111", "EXPDATE"=>"0115", "CARDTYPE"=>"0", "IAVS"=>"N"}