- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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:
- System will get an `access-token` based on `ClientID` and `ClientSecret`
- 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
- 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
Solved! Go to Solution.
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There're couple of points I would like to highlight:
- There is no issue in above code
- The create draft API is not returning the complete Invoice object, instead it is returning Invoice URL
- Based on Invoice URL received from draft invoice endpoint, I am sending another GET request to show invoice details endpoint.
- The show invoice details endpoint is now returning me the complete Invoice object.
- 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,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There're couple of points I would like to highlight:
- There is no issue in above code
- The create draft API is not returning the complete Invoice object, instead it is returning Invoice URL
- Based on Invoice URL received from draft invoice endpoint, I am sending another GET request to show invoice details endpoint.
- The show invoice details endpoint is now returning me the complete Invoice object.
- 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,

Haven't Found your Answer?
It happens. Hit the "Login to Ask the community" button to create a question for the PayPal community.
- PayPal Website Payments Pro in PayPal Payments Standard
- How to setup the language? in PayPal Payments Standard
- Why is the PaymentDate is different to the Timestamp in ExpressCheckout response? in NVP/SOAP APIs
- Get all available scopes in REST APIs
- UNPROCESSABLE_ENTITY TRANSACTION_REFUSED order error in PayPal Payments Standard