Unable to create draft PayPal invoice using v2 API version

puneetpandey
Contributor
Contributor

I am upgrading PayPal Invoicing feature from v1 to v2 (Because v1 is deprecated) in my Ruby on Rails application.

Since there's no official library/gem supporting v2 invoicing, so I decided to build everything as per this official documentation here: https://developer.paypal.com/docs/api/invoicing/v2.

The flow is like this:

  1. System will get an `access-token` based on `ClientID` and `ClientSecret`
  2. From this access-token, I will be generating a new `invoice_number` by sending curl request to: https://api.sandbox.paypal.com/v2/invoicing/generate-next-invoice-number
  3. Upon receiving the `invoice_number`, I am sending curl request to create draft invoice endpoint with all the required data

curl -v -X POST https://api.sandbox.paypal.com/v2/invoicing/invoice

 

The issue I am facing is with the last point. I am getting `201 created` response from create draft invoice endpoint but the endpoint is not returning me the complete invoice object along with Invoice ID.

Here's what I am getting:

 

 

"201"
{
  "rel"=>"self", 
  "href"=>"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-Z3K7-Y79X-36EM-ZQX8",
  "method"=>"GET"
}

 

 

 

If you try opening this link, you'll see this:

 

 

{
  "name":"AUTHENTICATION_FAILURE",
  "message":"Authentication failed due to invalid authentication credentials or a missing Authorization header.",
  "links": [
    {
      "href":"https://developer.paypal.com/docs/api/overview/#error",
      "rel":"information_link"
    }
  ]
}

 

 

Not sure what I am missing here!

Below is the code for reference:

 

 

require 'net/http'
require 'uri'
require 'json'

class PaypalInvoice
  def initialize order
    @order = order
    @Client_id = ENV['PAYPAL_CLIENT_ID']
    @Client_secret = ENV['PAYPAL_CLIENT_SECRET']
    @Base_url = ENV['AD_PP_ENV'] == 'sandbox' ? 'https://api.sandbox.paypal.com' : 'https://api.paypal.com'
    @paypal_access_token_identifier = 'paypal_access_token'
    @REQUEST_id ||= SecureRandom.uuid
  end

  def create_draft_invoice
    raise "Paypal token not found" unless Rails.cache.exist?(@paypal_access_token_identifier)

    invoice_number = "#141"
    sleep 5
    try = 0

    uri = URI.parse(@base_url + "/v2/invoicing/invoices")
    request = Net::HTTP::Post.new(uri)
    request['X-PAYPAL-SANDBOX-EMAIL-ADDRESS'] = ENV['PAYPAL_CLIENT_EMAIL']
    request['Authorization'] = "Bearer #{Rails.cache.fetch(@paypal_access_token_identifier)['access_token']}"
    request['Content-Type'] = 'application/json'
    request['PayPal-Request-Id'] = @REQUEST_id.to_s

    request.body = JSON.dump({
      "detail" => get_detail(invoice_number),
      "invoicer" => get_invoicer,
      "primary_recipients" => get_primary_recipients,
      "items" => items_info,
      "configuration" => {
        "partial_payment" => {
          "allow_partial_payment" => false,
        },
        "allow_tip" => false,
        "tax_calculated_after_discount" => true,
        "tax_inclusive" => true
      }
    })

    req_options = {
      use_ssl: uri.scheme == "https",
    }

    response = Net::HTTP.start(uri.host, uri.port, req_options) do |http|
      http.request(request)
    end

    p 'method: create_draft_invoice. response: '
    p response.code
    p JSON.parse(response.body)

    raise "Paypal token expired" if response.code.to_s == '401'

  rescue RuntimeError => error
    p "#{error.to_s}"
    try += 1
    access_token_response_status = get_new_access_token
    retry if access_token_response_status.to_s == '200' and try <= 1
  end
end

 

 

Login to Me Too
1 ACCEPTED SOLUTION

Accepted Solutions
Solved

puneetpandey
Contributor
Contributor

There're couple of points I would like to highlight:

  1. There is no issue in above code
  2. The create draft API is not returning the complete Invoice object, instead it is returning Invoice URL
  3. Based on Invoice URL received from draft invoice endpoint, I am sending another GET request to show invoice details endpoint.
  4. The show invoice details endpoint is now returning me the complete Invoice object.
  5. Based on Invoice object received from #4, I can now try marking an invoice as sent by sending another CURL request to send invoice endpoint,

View solution in original post

Login to Me Too
1 REPLY 1
Solved

puneetpandey
Contributor
Contributor

There're couple of points I would like to highlight:

  1. There is no issue in above code
  2. The create draft API is not returning the complete Invoice object, instead it is returning Invoice URL
  3. Based on Invoice URL received from draft invoice endpoint, I am sending another GET request to show invoice details endpoint.
  4. The show invoice details endpoint is now returning me the complete Invoice object.
  5. Based on Invoice object received from #4, I can now try marking an invoice as sent by sending another CURL request to send invoice endpoint,
Login to Me Too

Haven't Found your Answer?

It happens. Hit the "Login to Ask the community" button to create a question for the PayPal community.