PayflowPro(3pm)

πŸ“¦
version 1.01 Β· 2 versions
  • 1.01 Β· debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking (latest)
  • 1.01 Β· ubuntu jammy
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’³ PayflowPro(3pm) β€” the vibe check

okay bestie, so this is a page from the User Contributed Perl Documentation section of the manual β€” it's the PayflowPro(3pm) page, aka the lore drop for the Payflow Pro backend πŸ’…


✨ NAME ✨

Business::OnlinePayment::PayflowPro β€” the Payflow Pro backend for Business::OnlinePayment. literally what it says on the tin, no cap.


🌸 SYNOPSIS 🌸

here's the whole flow, verbatim, because we do not freestyle the code:

  use Business::OnlinePayment;

  my $tx = new Business::OnlinePayment(
      'PayflowPro',
      'vendor'  => 'your_vendor',
      'partner' => 'your_partner',
      'client_certification_id' => 'GuidUpTo32Chars',
  );

  # See the module documentation for details of content()
  $tx->content(
      type           => 'VISA',
      action         => 'Normal Authorization',
      description    => 'Business::OnlinePayment::PayflowPro test',
      amount         => '49.95',
      invoice_number => '100100',
      customer_id    => 'jsk',
      name           => 'Jason Kohles',
      address        => '123 Anystreet',
      city           => 'Anywhere',
      state          => 'GA',
      zip            => '30004',
      email          => 'ivan-payflowpro@420.am',
      card_number    => '4111111111111111',
      expiration     => '12/09',
      cvv2           => '123',
      order_number   => 'string',
      request_id     => 'unique_identifier_for_transaction',
  );

  $tx->submit();

  if ( $tx->is_success() ) {
      print(
          "Card processed successfully: ", $tx->authorization, "\n",
          "order number: ",                $tx->order_number,  "\n",
          "CVV2 response: ",               $tx->cvv2_response, "\n",
          "AVS code: ",                    $tx->avs_code,      "\n",
      );
  }
  else {
      my $info = "";
      $info = " (CVV2 mismatch)" if ( $tx->result_code == 114 );

      print(
          "Card was rejected: ", $tx->error_message, $info, "\n",
          "order number: ",      $tx->order_number,         "\n",
      );
  }

like… look at that error-handling branch. the CVV2 mismatch check? iconic. πŸŽ€


πŸ’– DESCRIPTION πŸ’–

so this module is a back end driver β€” it implements the interface that Business::OnlinePayment lays out, and it handles payments through PayPal's Payflow Pro Internet payment solution. that's the whole job. it shows up, it does the thing, it slays. ✨

and if you wanna know all about the interface this module supports, go read Business::OnlinePayment. it's the blueprint, bestie.


πŸ‘‘ Standard methods πŸ‘‘

set_defaults()

this one sets the 'server' attribute to 'payflowpro.paypal.com' and the port attribute to '443'. and also? it sets up all the "Module specific methods" we're about to talk about below. multitasking queen. πŸ’…

submit()

that's it. that's the entry. (it does the submitting, obviously.)


πŸ¦‹ Unofficial methods πŸ¦‹

these ones are not officially part of the standard Business::OnlinePayment interface β€” as of version 3.00_06 anyway β€” BUT multiple gateway modules support them and they're expected to get standardized soon. so they're like, unofficially official. iykyk.

  • order_number()
  • avs_code()
  • cvv2_response()

🌈 Module specific methods 🌈

these next ones are not currently part of the standard Business::OnlinePayment interface. they're the specials, the house menu, the extras. πŸ“

client_certification_id()

this gets/sets the X-VPS-VITCLIENTCERTIFICATION-ID, which is REQUIRED and defaults to "ClientCertificationIdNotSet". the Website Payments Pro HTTPS Interface Developer's Guide describes it like this, and i'm quoting fr fr:

"A random globally unique identifier (GUID) that is currently required. This requirement will be removed in the future. At this time, you can send any alpha-numeric ID up to 32 characters in length. NOTE: Once you have created this ID, do not change it. Use the same ID for every transaction."

so make one, keep it forever, periodt. πŸ’€

client_timeout()

this is the timeout value, in seconds β€” after that many seconds, the transaction should get aborted. defaults to 45, which is the value the Website Payments Pro HTTPS Interface Developer's Guide recommends. so like, 45 is the canon number.

debug()

turns debugging on or off. whatever value you put here also sets $Business::OnlinePayment::HTTPS::DEBUG inside submit(), which helps when you're troubleshooting problems. 🧚

expdate_mmyy()

this method takes a single scalar argument β€” typically the value sitting in $content{expiration} β€” and it tries to parse it and format it into MMYY format, because that's what the PayflowPro spec requires. if it can't parse the expiration date? it just leaves it as-is and lets the PayflowPro system try to handle it however it handles it. no drama, no crash. πŸ™ˆ

request_id()

highly recommend you set your own unique request_id for every single transaction in %content. a request_id is REQUIRED by the PayflowPro processor. and if you don't set one? then Digest::MD5 gets used to try and generate a request_id for the transaction. so like, you can let the module do it, but setting your own is the move. ⭐

Deprecated methods

these are deprecated and may be removed in a future release. values for vendor and partner should now be set as arguments to Business::OnlinePayment->new() instead. and the cert_path value was only ever there to support passing a path to PFProAPI.pm β€” that's a Perl module/SDK from Verisign/Paypal β€” which is no longer used. it's giving "old era, retired." 🫢

  • vendor()
  • partner()
  • cert_path()
  • cvv2_code()

πŸŽ€ Settings πŸŽ€

here are the default settings that exist, bestie:

  • server β€” payflowpro.paypal.com, or pilot-payflowpro.paypal.com if test_transaction() is TRUE
  • port β€” 443

πŸ’œ Handling of content(%content) πŸ’œ

these rules apply to your content(%content) data:

action

if 'action' matches one of these keys, it gets replaced by the value on the right:

  'normal authorization' => 'S', # Sale transaction
  'credit'               => 'C', # Credit (refund)
  'authorization only'   => 'A', # Authorization
  'post authorization'   => 'D', # Delayed Capture
  'void'                 => 'V',

and heads up β€” if 'action' is 'C', 'D' or 'V' and 'order_number' is not set, then 'amount', 'card_number' and 'expiration' must be set. no skips, no shortcuts. 😭

type

if 'type' matches one of these keys, it gets replaced by the value on the right:

  'visa'               => 'C',
  'mastercard'         => 'C',
  'american express'   => 'C',
  'discover'           => 'C',
  'cc'                 => 'C',

the value of 'type' is used to set transaction_type(). right now this module only supports a transaction_type() of 'C' β€” any other value will cause Carp::croak() to be called inside submit(). so yeah, don't test it. πŸ’€

Note: Payflow Pro supports multiple credit card types, including: American Express/Optima, Diners Club, Discover/Novus, Enroute, JCB, MasterCard and Visa. so the gateway is versatile, this module is just picky.


🩷 Setting Payflow Pro parameters from content(%content) 🩷

here's the mapping rules β€” how data gets turned into Payflow Pro parameters from content(%content). look at this table, it's giving detailed and organized:

      # PFP param => $content{<key>}
      VENDOR      => $self->vendor ? \( $self->vendor ) : 'login',
      PARTNER     => \( $self->partner ),
      USER        => 'login',
      PWD         => 'password',
      TRXTYPE     => 'action',
      TENDER      => 'type',
      ORIGID      => 'order_number',
      COMMENT1    => 'description',
      COMMENT2    => 'invoice_number',

      ACCT        => 'card_number',
      CVV2        => 'cvv2',
      EXPDATE     => \( $month.$year ), # MM/YY from 'expiration'
      AMT         => 'amount',

      FIRSTNAME   => 'first_name',
      LASTNAME    => 'last_name',
      NAME        => 'name',
      EMAIL       => 'email',
      COMPANYNAME => 'company',
      STREET      => 'address',
      CITY        => 'city',
      STATE       => 'state',
      ZIP         => \$zip, # 'zip' with non-alphanumerics removed
      COUNTRY     => 'country',

      # As of 8/18/2009: CUSTCODE appears to be cut off at 18
      # characters and isn't currently reportable.  Consider storing
      # local customer ids in the COMMENT1/2 fields as a workaround.
      CUSTCODE    => 'customer_id',

      SHIPTOFIRSTNAME => 'ship_first_name',
      SHIPTOLASTNAME  => 'ship_last_name',
      SHIPTOSTREET    => 'ship_address',
      SHIPTOCITY      => 'ship_city',
      SHIPTOSTATE     => 'ship_state',
      SHIPTOZIP       => 'ship_zip',
      SHIPTOCOUNTRY   => 'ship_country',
real talk: the CUSTCODE note above is a genuine caveat β€” as of 8/18/2009 it appears to be cut off at 18 characters and isn't currently reportable, so consider storing local customer ids in the COMMENT1/COMMENT2 fields as a workaround. noted, logged, remembered. πŸ“

and the required Payflow Pro parameters for credit card transactions are:

  TRXTYPE TENDER PARTNER VENDOR USER PWD ORIGID

memorize it. that's the checklist. βœ…


🌟 Mapping Payflow Pro transaction responses to object methods 🌟

these methods give you access to the transaction response data that comes back from a Payflow Pro request β€” after submit() is called, obviously:

order_number()

returns the PNREF field, also known as the PayPal Reference ID β€” a unique number that identifies the transaction. it's the transaction's whole identity. main character energy. πŸ‘‘

result_code()

returns the RESULT field β€” the numeric return code that tells you the outcome of the attempted transaction.

a RESULT of 0 (zero) means the transaction was approved and is_success() will return '1' (one/TRUE). any other RESULT value means a decline or an error, and is_success() will return '0' (zero/FALSE). so like, zero means you ate. anything else? πŸ’€

error_message()

returns the RESPMSG field β€” a response message that comes back with the transaction result.

authorization()

returns the AUTHCODE field β€” the approval code obtained from the processing network. πŸŽ€

avs_code()

returns a combination of the AVSADDR and AVSZIP fields from the transaction result. the value in avs_code breaks down like this:

  Y     - Address and ZIP match
  A     - Address matches but not ZIP
  Z     - ZIP matches but not address
  N     - no match
  undef - AVS values not available

so Y is the slay, undef is the shrug. 🀷

cvv2_response()

returns the CVV2MATCH field β€” a response message that comes back with the transaction result.


🧚 COMPATIBILITY 🧚

as of 0.07, this module talks to the Payflow gateway directly and no longer needs the Payflow Pro SDK or any other download. glow-up. thanks to Phil Lobbes for this great work, and Josh Rosenbaum for additional enhancements and bug fixes. 🫢


⭐ AUTHORS ⭐

  • Ivan Kohler <ivan-payflowpro@420.am>
  • Phil Lobbes <phil at perkpartners.com>

based on Business::OnlinePayment::AuthorizeNet, which was written by Jason Kohles.


🌈 SEE ALSO 🌈

perl(1), Business::OnlinePayment, Carp, and the PayPal Integration Center Payflow Pro resources at <https://www.paypal.com/IntegrationCenter/ic_payflowpro.html>


and that's the whole page, bestie β€” this was PayflowPro(3pm) from perl v5.34.0, dated 2022-06-30. go forth and process those payments responsibly, mwah πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from