Length of item name in PayPal Express Checkout for Digital Goods - paypal

I am integrating PayPal Express Checkout for Digital Goods on my website and I am having trouble displaying the items which the user has selected on the PayPal review page -- the item displays but its name is cut off at 19 characters, which is not very lengthy for identifying something.
Is this just a limit of the interface, or is there something I can do to make the full name (or at least 40 or so characters of it) display? I know I'm passing in the full string because it shows if I hover over the truncated description.
If it is a limit of the interface, is it always 19 characters in every browser, including mobile? Is it by em-length? If I know this is the hard limit I can massage the item names so that I don't appear to be selling "Attending Membershi".
I'm using the basic code provided by the PayPal integration wizard. I'm filling my $items array to pass to SetExpressCheckoutDG in PHP like so:
$items[] = array('name' => 'Attending Membership for [convention and date]', 'amt' => $attending_cost, 'qty' => 1);
$resArray = SetExpressCheckoutDG( $paymentAmount, $currencyCodeType, $paymentType, $returnURL, $cancelURL, $items );
and then retrieving them with GetExpressCheckoutDetails and resending them via ConfirmPayment:
$res = GetExpressCheckoutDetails( $_REQUEST['token'] );
$items = array();
$i = 0;
while(isset($res["L_PAYMENTREQUEST_0_NAME$i"])) {
$items[] = array('name' => $res["L_PAYMENTREQUEST_0_NAME$i"], 'amt' => $res["L_PAYMENTREQUEST_0_AMT$i"], 'qty' => $res["L_PAYMENTREQUEST_0_QTY$i"]);
$i++;
}
$resArray = ConfirmPayment ( $token, $paymentType, $currencyCodeType, $payerID, $finalPaymentAmount, $items );
and getting this: http://i.imgur.com/9ST9mm7.png

PayPal checkout pages display the item name based on the layout that is rendered.
Item length supported for :
Digital Goods - 19 characters
Express Checkout (Physical) old layout = 35 characters
Express Checkout (Physical) new layout = 13 characters
In-Context Checkout - 19 Characters.
It's the intended behaviour to not to show the entire character length and shows upon hover

Related

Contact Form 7 - how to add several number fields dynamically

I am currently working on a web project where users should be able to have a list of brochures (list comes from custom post type) and enter the amount they would like to order individually for each of them via a simple contact form. My idea was to generate a dynamic list of number fields with the 'wpcf7_form_tag_data_option' hook like in this article:
Dynamicly populate Contact form 7 input fields with current user info when logged in in Wordpress website
So if i am using the select or checkbox field type within contact form 7:
[select anzahlKataloge data:brochures]
or
[checkbox anzahlKataloge data:brochures]
and functions.php:
add_filter('wpcf7_form_tag_data_option', function($n, $options, $args) {
if (in_array('brochures', $options)){
$query = new WP_Query(
array( 'orderby' => 'date', 'order' => 'DESC', 'posts_per_page' => '100', 'post_type' => 'prospekte')
);
while($query->have_posts()) : $query->the_post();
$title = get_the_title();
$brochures[] = $title;
endwhile;
return $brochures;
}
return $n;
}, 10, 3);
It generates the select or checkbox list just fine but i would actually need it to work with the number field type:
[number anzahlKataloge data:brochures]
or with text type:
[text anzahlKataloge data:brochures]
Any help is much appreciated.
Best Regards,
Rafael

Bug with negative amounts in PayPal API

I'm trying to use a negative amount with the PayPal Adaptive Payments API. To start with, this seems to work:
'item' => [
{
'itemPrice' => '25.00',
'name' => 'Cryptex - 16Gb USB Drive',
'price' => '25',
'itemCount' => 1
},
{
'quantity' => 1,
'name' => 'Special Discount',
'price' => '-2.50'
},
{
'itemPrice' => '5.00',
'name' => 'Shipping',
'price' => '5.00',
'itemCount' => 1
}
]
Here is an example of what I see after submitting this as JSON, and updating the items:
As you can see, the price IS correct ... yet there is no sign of the discounted amount? Its obviously taking it into account - otherwise the price would have been £30, not £27.50 (which is after the £2.50 discount)
What gives? Is this a bug in PayPals system?
FWIW, the emails are also broken - they don't show the discount amount at all.
UPDATE: I've opened a ticket with PayPal tech support, as I'm pretty sure this is a bug with their system, and not something that can be fixed this end :( Damn annoying!
UPDATE 2: Reply from PayPal:
PayPal Adaptive Payments do not support negative item values. Since you did not pass the <itemPrice> in your API Call, the system did not throw the following error message:
[errorId] => 580022
[domain] => PLATFORM
[subdomain] => Application
[severity] => Error
[category] => Application
[message] => Invalid request parameter: itemPrice cannot be negative
I can see that the following was submitted to PayPal:
<item>
<name>Special Discount</name>
<identifier></identifier>
<price>-2.50</price>
<itemPrice></itemPrice>
<itemCount></itemCount>
<any>[quantity: null]</any>
</item>
This object is basically incomplete and in order to apply discounts, you should apply them > onto the price for the main item and then submit it to PayPal.
I'm really not sure what they're suggestion I do? An example cart, would be:
Item 1 - £10
Item 2 - £20
Item 3 - £50
Item 4 - £10
Delivery - £5
Total - £95
As an encouragement, we sometimes will offer coupons... so it could be "£10 off orders over £50". So in the above case above, it would drop the overall price to £85.
I'm really not sure what they are suggesting as an alternative?
Interesting. Normal payments don't have that restriction (I pass a negative amount item just like what you describe on a frequent basis).
What they're telling you to do is take the discount off another item. So your example cart with that discount would be
Item 1 - £10
Item 2 - £20
Item 3 - £40 <-- Removed £10 discount
Item 4 - £10
Delivery - £5
Total - £85 <-- total reflects this

How do I populate Stripe's description field on subscription charge?

I can populate Business::Stripe's description field for one off charges with the below code :
use Business::Stripe; # Version 0.4
# Create Customer
my $customer = $stripe->api('post', 'customers',
card => $stripeToken,
description => $username,
);
# Charge
my $charge = $stripe->api('post', 'charges',
customer => $customer,
currency => $currency,
description => 'my description here no probs',
amount => $amount,
);
But when I create a customer a customer and assign them to a subscription plan I can't see how to populate the description of the charge made each billing period.
# Create Customer and subscribe to a plan
my $customer = $stripe->api('post', 'customers',
card => $stripeToken,
description => 'description here is for the customer not the monthly charge',
plan => $plan
);
I want to be able to add a description to the charge that happens each billing period.
The API doesn't seem to show a way but the field is editable via the strie dashboard.
Stripe is thinking about auto-populating the charge description on invoices, but that's not a feature that exists yet. In the meantime, once the invoice.payment_succeeded event occurs, you can get the charge ID from that event data. Then you can update the charge's description via the API:
https://stripe.com/docs/api#update_charge
Hope that helps,
Larry
PS I work on Support at Stripe.

How to get paykey using Paypal Adeptive and make successful checkout in checkout?

i am using paypal adaptive parallel payments using light box so that user resides on my own site without redirections.
I am simply want when i click on payment button i will get dynamic key in the form and so on the posting form lightbox opens up and i gets payment from sender and split the money in 2 accounts.
paypal business account:
mohsin#balianti.com that is my site admin account as well. who will receive 10% from total amount.
sanbox account that i created in mohsin#balianti.com sandbox account options: mmskit#outlook.com that will receive 90% of total money.
so mohsin#balianti.com as a site admin and holding business account will receive 10% while other receiver will receive 90%.
means total money will split in both accounts.
hope you will got my point.
the problem is that:
1- i am not getting paykey from paypal.
2- i am unable to do the transaction in light box.
3- i am unable to slipt the money in 2 receivers and so unable to complete to process.
My HTML Code:
<html>
<head>
<script src="https://www.paypalobjects.com/js/external/dg.js" type="text/javascript"></script>
</head>
<body>
<!--https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay?expType=light&payKey=AP-5S482348KH512131U-->
<form action="https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay?expType=light&payKey=NOT KNOW HOW TO GET THIS PAY KEY ON THE BUTTON CLICK" target="PPDGFrame" class="standard">
<label for="buy">Buy Now:</label>
<input type="image" id="submitBtn" value="Pay with PayPal" src="https://www.paypalobjects.com/en_US/i/btn/btn_paynowCC_LG.gif">
</form>
<script type="text/javascript" charset="utf-8">
var embeddedPPFlow = new PAYPAL.apps.DGFlow({trigger: 'submitBtn'});
</script>
</body>
</html>
My Config.php file:
<?php
/**
* Timezone Setting
* List of Supported Timezones: http://www.php.net/manual/en/timezones.php
*/
date_default_timezone_set('America/Chicago');
/**
* Enable Sessions
* Checks to see if a session_id exists. If not, a new session is started.
*/
if(!session_id()) session_start();
/**
* Sandbox Mode - TRUE/FALSE
* Check the domain of the current page and set $sandbox accordingly.
* This allows you to automatically use Sandbox or Live credentials throughout
* your application based on what server the app is running from.
*
* I like to do this so I don't forget to update Sandbox credentials to Live
* prior to uploading files to a production server.
*
* In this case, it's checking to see if the current URL is http://sandbox.domain.*
* If so, $sandbox is true and the PayPal sandbox will be used throughout. If not,
* we'll assume it must be a live transaction and will use live credentials throughout.
*
* Following this pattern will allow you to create your own http://sandbox.domain.com test server,
* and then any time your code runs from that server, PayPal's sandbox will be used automatically.
*
* If you would rather just set $sandbox to true/false on your own that's fine,
* but you have to make sure your live server always uses false and your test server
* always uses true. It's easy to forget this and up with real customers processing
* payments from your live site on the PayPal sandbox.
*/
$host_split = explode('.',$_SERVER['HTTP_HOST']);
$sandbox = $host_split[0] == 'sandbox' && $host_split[1] == 'domain' ? TRUE : FALSE;
$domain = $sandbox ? 'http://sandbox.domain.com/' : 'http://lahori.org/mydev/themusicnetwork/';
/**
* Enable error reporting if running in sandbox mode.
*/
if($sandbox)
{
error_reporting(E_ALL|E_STRICT);
ini_set('display_errors', '1');
}
/*
* PayPal API Version
* ------------------
* The library is currently using PayPal API version 109.0.
* You may adjust this value here and then pass it into the PayPal object when you create it within your scripts to override if necessary.
*/
$api_version = '109.0';
/*
* PayPal Application ID
* --------------------------------------
* The application is only required with Adaptive Payments applications.
* You obtain your application ID but submitting it for approval within your
* developer account at http://developer.paypal.com
*
* We're using shorthand if/else statements here to set both Sandbox and Production values.
* Your sandbox values go on the left and your live values go on the right.
* The sandbox value included here is a global value provided for developrs to use in the PayPal sandbox.
*/
$application_id = $sandbox ? 'APP-80W284485P519543T' : '';
/*
* PayPal Developer Account Email Address
* This is the email address that you use to sign in to http://developer.paypal.com
*/
$developer_account_email = 'mohsin#balianti.com';
/*
* PayPal Gateway API Credentials
* ------------------------------
* These are your PayPal API credentials for working with the PayPal gateway directly.
* These are used any time you're using the parent PayPal class within the library.
*
* We're using shorthand if/else statements here to set both Sandbox and Production values.
* Your sandbox values go on the left and your live values go on the right.
*
* You may obtain these credentials by logging into the following with your PayPal account: https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run
*/
$api_username = $sandbox ? 'mohsin_api1.balianti.com' : 'LIVE_API_USERNAME';
$api_password = $sandbox ? 'DAQQ3QK5LTHHWGYV' : 'LIVE_API_PASSWORD';
$api_signature = $sandbox ? 'Ad9JZLf8.13dlHmFgFft2NVbaPK4AvTXPIYEMvf.CyBXiGxnrmbQG4l2' : 'LIVE_API_SIGNATURE';
/*
* Payflow Gateway API Credentials
* ------------------------------
* These are the credentials you use for your PayPal Manager: http://manager.paypal.com
* These are used when you're working with the PayFlow child class.
*
* We're using shorthand if/else statements here to set both Sandbox and Production values.
* Your sandbox values go on the left and your live values go on the right.
*
* You may use the same credentials you use to login to your PayPal Manager,
* or you may create API specific credentials from within your PayPal Manager account.
*/
$payflow_username = $sandbox ? 'SANDBOX_PAYFLOW_USERNAME' : 'LIVE_PAYFLOW_USERNAME';
$payflow_password = $sandbox ? 'SANDBOX_PAYFLOW_PASSWORD' : 'LIVE_PAYFLOW_PASSWORD';
$payflow_vendor = $sandbox ? 'SANDBOX_PAYFLOW_VENDOR' : 'LIVE_PAYFLOW_VENDOR';
$payflow_partner = $sandbox ? 'SANDBOX_PAYFLOW_PARTNER' : 'LIVE_PAYFLOW_PARTNER';
/*
* PayPal REST API Credentials
* ---------------------------
* These are the API credentials used for the PayPal REST API.
* These are used any time you're working with the REST API child class.
*
* You may obtain these credentials from within your account at http://developer.paypal.com
*/
$rest_client_id = $sandbox ? 'AUjqAhB6ZWMudj58C_NAC0kA58EmNCl2LPFlmaX76t1e0kVu-GwALjzVTBwR' : 'LIVE_CLIENT_ID';
$rest_client_secret = $sandbox ? 'EPXlgBAIfaptG15JI7OxxZK1GNxgfAqQg5uhmllzdF1FIE5hjEhsIBbrwfbV' : 'LIVE_SECRET_ID';
/*
* PayPal Finance Portal API
* -------------------------
* These are credentials used for obtaining a PublisherID used in Bill Me Later Banner code.
* As of now, these are specialized API's and you must obtain credentials directly from a PayPal rep.
*/
$finance_access_key = $sandbox ? 'SANDBOX_ACCESS_KEY' : 'LIVE_ACCESS_KEY';
$finance_client_secret = $sandbox ? 'SANDBOX_CLIENT_SECRET' : 'LIVE_CLIENT_SECRET';
/**
* Third Party User Values
* These can be setup here or within each caller directly when setting up the PayPal object.
*/
$api_subject = ''; // If making calls on behalf a third party, their PayPal email address or account ID goes here.
$device_id = '';
$device_ip_address = $_SERVER['REMOTE_ADDR'];
?>
My PHP Code i get from angel's eye paypal class:
<?php
// Include required library files.
require_once('config.php');
require_once('paypal.class.php');
require_once('paypal.adaptive.class.php');
// Create PayPal object.
$PayPalConfig = array(
'Sandbox' => $sandbox,
'DeveloperAccountEmail' => $developer_account_email,
'ApplicationID' => $application_id,
'DeviceID' => $device_id,
'IPAddress' => $_SERVER['REMOTE_ADDR'],
'APIUsername' => $api_username,
'APIPassword' => $api_password,
'APISignature' => $api_signature,
'APISubject' => $api_subject
);
$PayPal = new PayPal_Adaptive($PayPalConfig);
// Prepare request arrays
$PayRequestFields = array(
'ActionType' => 'PAY', // Required. Whether the request pays the receiver or whether the request is set up to create a payment request, but not fulfill the payment until the ExecutePayment is called. Values are: PAY, CREATE, PAY_PRIMARY
'CancelURL' => $domain.'cancel.php', // Required. The URL to which the sender's browser is redirected if the sender cancels the approval for the payment after logging in to paypal.com. 1024 char max.
'CurrencyCode' => 'USD', // Required. 3 character currency code.
'FeesPayer' => 'EACHRECEIVER', // The payer of the fees. Values are: SENDER, PRIMARYRECEIVER, EACHRECEIVER, SECONDARYONLY
'IPNNotificationURL' => '', // The URL to which you want all IPN messages for this payment to be sent. 1024 char max.
'Memo' => '', // A note associated with the payment (text, not HTML). 1000 char max
'Pin' => '', // The sener's personal id number, which was specified when the sender signed up for the preapproval
'PreapprovalKey' => '', // The key associated with a preapproval for this payment. The preapproval is required if this is a preapproved payment.
'ReturnURL' => $domain.'return.php', // Required. The URL to which the sener's browser is redirected after approvaing a payment on paypal.com. 1024 char max.
'ReverseAllParallelPaymentsOnError' => '', // Whether to reverse paralel payments if an error occurs with a payment. Values are: TRUE, FALSE
'SenderEmail' => '', // Sender's email address. 127 char max.
'TrackingID' => '' // Unique ID that you specify to track the payment. 127 char max.
);
$ClientDetailsFields = array(
'CustomerID' => '', // Your ID for the sender 127 char max.
'CustomerType' => '', // Your ID of the type of customer. 127 char max.
'GeoLocation' => '', // Sender's geographic location
'Model' => '', // A sub-identification of the application. 127 char max.
'PartnerName' => 'Always Give Back' // Your organization's name or ID
);
$FundingTypes = array('ECHECK', 'BALANCE', 'CREDITCARD');
$Receivers = array();
$Receiver = array(
'Amount' => '10.00', // Required. Amount to be paid to the receiver.
'Email' => 'mohsin#balianti.com', // Receiver's email address. 127 char max.
'InvoiceID' => '', // The invoice number for the payment. 127 char max.
'PaymentType' => 'GOODS', // Transaction type. Values are: GOODS, SERVICE, PERSONAL, CASHADVANCE, DIGITALGOODS
'PaymentSubType' => '', // The transaction subtype for the payment.
'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => ''), // Receiver's phone number. Numbers only.
'Primary' => 'TRUE' // Whether this receiver is the primary receiver. Values are boolean: TRUE, FALSE
);
array_push($Receivers,$Receiver);
$Receiver = array(
'Amount' => '5.00', // Required. Amount to be paid to the receiver.
'Email' => 'mmskit#outlook.com', // Receiver's email address. 127 char max.
'InvoiceID' => '', // The invoice number for the payment. 127 char max.
'PaymentType' => 'GOODS', // Transaction type. Values are: GOODS, SERVICE, PERSONAL, CASHADVANCE, DIGITALGOODS
'PaymentSubType' => '', // The transaction subtype for the payment.
'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => ''), // Receiver's phone number. Numbers only.
'Primary' => 'false' // Whether this receiver is the primary receiver. Values are boolean: TRUE, FALSE
);
array_push($Receivers,$Receiver);
$SenderIdentifierFields = array(
'UseCredentials' => '' // If TRUE, use credentials to identify the sender. Default is false.
);
$AccountIdentifierFields = array(
'Email' => '', // Sender's email address. 127 char max.
'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => '') // Sender's phone number. Numbers only.
);
$PayPalRequestData = array(
'PayRequestFields' => $PayRequestFields,
'ClientDetailsFields' => $ClientDetailsFields,
'FundingTypes' => $FundingTypes,
'Receivers' => $Receivers,
'SenderIdentifierFields' => $SenderIdentifierFields,
'AccountIdentifierFields' => $AccountIdentifierFields
);
// Pass data into class for processing with PayPal and load the response array into $PayPalResult
$PayPalResult = $PayPal->Pay($PayPalRequestData);
if(!$this->paypal_adaptive->APICallSuccessful($PayPalResult['Ack']))
{
$errors = array('Errors'=>$PayPalResult['Errors']);
// Write the contents of the response array to the screen for demo purposes.
echo '<pre />';
print_r($errors);
exit();
}
else
{
header('Location: '.$PayPalResult['RedirectURL']);
$ExecutePaymentFields = array(
'PayKey' => $PayPalResult['PayKey'],
'FundingPlanID' => ''
);
$PayPalRequestData = array('ExecutePaymentFields' => $ExecutePaymentFields);
$PayPalResult = $PayPal->ExecutePayment($PayPalRequestData);
if(!$PayPalResult)
{
$errors = array('Errors'=>$PayPalResult['Errors']);
echo '<pre />';
print_r($errors);
exit();
}
else
{
echo '<pre />';
print_r($PayPalResult);
}
}
if($PayPal->APICallSuccessful($PayPalResult['Ack']))
{
// Redirect to PayPal so user can complete payment.
header('Location: '.$PayPalResult['RedirectURL']);
}
else
{
// Error
echo '<pre />';
print_r($PayPalResult['Errors']);
exit();
}
?>
my login information and whole detailed level information i received from paypal.
REST API CREDENTIALS
Test credentials
Your test credentials are enabled for all features in your app.
Test account:
mohsin-facilitator#balianti.com
Endpoint: api.sandbox.paypal.com
Client ID: AUjqAhB6ZWMudj58C_NAC0kA58EmNCl2LPFlmaX76t1e0kVu-GwALjzVTBwR
Secret: EPXlgBAIfaptG15JI7OxxZK1GNxgfAqQg5uhmllzdF1FIE5hjEhsIBbrwfbV
Here is your API signature:
API Username: mohsin_api1.balianti.com
API Password: DAQQ3QK5LTHHWGYV
Signature: Ad9JZLf8.13dlHmFgFft2NVbaPK4AvTXPIYEMvf.CyBXiGxnrmbQG4l2
Copy and paste the PayPal settings above into the API/Integration section of your Magento Configuration page.
You have successfully saved your preferences. Please use the following identity token when setting up Payment Data Transfer on your website.
A9XxF-vXyH3-kPYVX0dDDcojmBxvMidXnmn846gxQD0ehzXM4Xjva0VL6RW
http://developer.paypal.com
mohsin#balianti.com
m#h$!nBali
please please help me resolving the whole issue. i am waiting for serious replies please.
Thank You All.
I took your code and ran it on my server here.
The first thing I notice is that you have everything commented out below the $PayPalResult getting loaded, so you didn't have anything actually happening with that result. No output to screen or back to the requesting client.
When I run it with my credentials and look at the actual result, this is what I'm getting.
[Errors] => Array
(
[0] => Array
(
[Receiver] =>
[Category] => Application
[Domain] => PLATFORM
[ErrorID] => 520009
[ExceptionID] =>
[Message] => Account mohsin#balianti.com is restricted
[Parameter] => mohsin#balianti.com
[Severity] => Error
[Subdomain] => Application
)
)
[Ack] => Failure
[Build] => 10273932
[CorrelationID] => 471e9fbfa0053
[Timestamp] => 2014-03-29T09:45:56.631-07:00
So it seems that there is something wrong with the receiver account you're using on this. When I look into that more I see that you've got the same receiver set as both a primary and a secondary receiver on this same payment.
Once I replaced your receiver email address with 2 separate emails from my own sandbox accounts, I got a successful response.
[Ack] => Success
[Build] => 10273932
[CorrelationID] => 9afd1342ebf17
[Timestamp] => 2014-03-29T09:50:00.472-07:00
[PayKey] => AP-8FY50816521434738
[PaymentExecStatus] => CREATED
So then I went back and tried your account as a receiver along with one of my accounts, but I wound up with the same error about the account being restricted.
So, I'm not sure why that account would be restricted, especially on the sandbox. It doesn't look like a sandbox email account, though. Is it one? You need to make sure you're using sandbox accounts when testing on the sandbox.
If you're actually hitting the live server and getting the same error then you'll need to contact PayPal for help with what's wrong with that account.
You may be getting a different error, though, if you're running live. To check that you need to look at the actual result that is coming back to $PayPalResult. Again, you've got all of that commented out in your code, so it wouldn't even be returning a result back to your client request.
please see.:
Array
(
[Errors] => Array
(
[0] => Array
(
[Receiver] =>
[Category] => Application
[Domain] => PLATFORM
[ErrorID] => 580022
[ExceptionID] =>
[Message] => Invalid request parameter: payKey cannot be null
[Parameter] => payKey
[Severity] => Error
[Subdomain] => Application
)
)
[Ack] => Failure
[Build] => 10273932
[CorrelationID] => 2d63bc22401c7
[Timestamp] => 2014-04-15T02:27:08.040-07:00
[PaymentExecStatus] =>
[XMLRequest] => ReturnAllen_US
[XMLResponse] => 2014-04-15T02:27:08.040-07:00Failure2d63bc22401c710273932580022PLATFORMApplicationErrorApplicationInvalid request parameter: payKey cannot be nullpayKeynull
)
odftetretArray
(
[0] => Array
(
[Receiver] =>
[Category] => Application
[Domain] => PLATFORM
[ErrorID] => 580022
[ExceptionID] =>
[Message] => Invalid request parameter: payKey cannot be null
[Parameter] => payKey
[Severity] => Error
[Subdomain] => Application
)
)

Express Checkout Digital Goods - tax line item doesn't display

I am calling SetExpressCheckout and handing in some tax. The Grand total in the paypal checkout screen reflects the tax (as expected) but there is no line item showing the tax. This is very confusing for customers. It appears like the grand total is "just higher" than the item price, for no apparent reason. I can't believe paypal would build it this way, so I assume I must be doing something wrong.
Here's a screenshot:
Here is my REQUEST:
VERSION = 97.0
METHOD = SetExpressCheckout
RETURNURL = http://[removed...]
CANCELURL = http://[removed...]
PAYMENTREQUEST_0_PAYMENTACTION = Sale
PAYMENTREQUEST_0_CURRENCYCODE = USD
PAYMENTREQUEST_0_ITEMAMT = 1
L_PAYMENTREQUEST_0_NAME0 = Widget1
L_PAYMENTREQUEST_0_NUMBER0 = Widget1
L_PAYMENTREQUEST_0_AMT0 = 1
PAYMENTREQUEST_0_TAXAMT = 0.06
PAYMENTREQUEST_0_AMT = 1.06
L_PAYMENTREQUEST_0_QTY0 = 1
L_PAYMENTREQUEST_0_ITEMCATEGORY0 = Digital
SOLUTIONTYPE = Sole
REQCONFIRMSHIPPING = 0
NOSHIPPING = 1
I also tried adding tax as an add'l "L_" line item for tax, but that makes it worse. It increases the line item itself by the tax amount, so the customer doesn't know they're paying tax, they just think the item price is higher.
Please help.
Don't know if you still need help but I found a way to add tax simply by adding the tax as an additional item.
This also allowed me to name the tax....:
// to add anothe item, uncomment the lines below and comment the line above
$items[] = array('name' => 'TVA', 'amt' => $tvaAmount1, 'qty' => 1);
// $items[] = array('name' => 'Item Name2', 'amt' => $itemAmount2, 'qty' => 1);
$paymentAmount = $paymentAmount + $tvaAmount1;