PagSeguro integration - brazilian market means of payment

  1. 3 weeks ago

    Leonidas B

    Nov 19 Macaé, RJ, Brazil

    Hello,

    I'm having a hard time trying to develop a payment tool for PagSeguro, one of the leading payment platforms in Brazil.

    Their documentation says the app should POST to a specific endpoint with some parameters. That can be done with HTTPSecureSocket. Problem is the response I get is:

    HTTP Status 406 - No match for accept header
    
    type Status report
    
    message No match for accept header
    
    description The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers (No match for accept header).

    I believe the Header settings of the request seems to be ok.

    Is there something I'm missing in my code below?

    Public Sub Get_Sale_ID()
    
    Dim mylink As String = "https://ws.sandbox.pagseguro.uol.com.br/v2/sessions"
    Dim dadosform As New Dictionary
    
    dadosform.Value("appID") = "zepipayer"
    dadosform.Value("appKey") = "5863542E0A0A90B77499EF9E6F80CACD" 
    
    Dim buscador As New HTTPSecureSocket
    
    buscador.requestHeaders.DeleteAllHeaders
    
    buscador.requestHeaders.AppendHeader("Content-Type", "application/json;charset=ISO-8859-1")
    buscador.requestHeaders.AppendHeader("Accept", "application/vnd.pagseguro.com.br.v3+json;charset=ISO-8859-1")
    buscador.requestHeaders.AppendHeader("Accept-Language", "utf-8, iso-8859-1;q=0.5, *;q=0.1")
    buscador.requestHeaders.AppendHeader("Accept-Charset", "iso-8859-1")
      
    buscador.SetFormData(dadosform)
    
    buscador.Secure = True
    buscador.ConnectionType = HTTPSecureSocket.TLSv1
    
    AddHandler buscador.PageReceived, WeakAddressOf Recebido_Secure
    
    buscador.Post(mylink)
    
    End Sub

    This is their documentation page:

    https://devs.pagseguro.uol.com.br/docs/pagamento-recorrente-endpoints-da-api

    This is what I have for receiving data from the webpage:

    Public Sub Recebido_Secure(sender As HTTPSecureSocket, s1 As String, i1 As Integer, ih As InternetHeaders, s2 As String)
      dim dt As New Date
      
      TextArea1.Text = ""
      
      TextArea1.AppendText "RECEIVED " + dt.SQLDateTime + " " + EndOfLine
      
      TextArea1.AppendText Str(sender.ErrorCode) + EndOfLine
      TextArea1.AppendText s1 + EndOfLine
      TextArea1.AppendText str(i1) + EndOfLine
      
      HTMLViewer1.LoadPage(s2)
      
    End Sub

    Thanks in advance! Any help is welcome...

    Hello,

    Here is a first attempt at making this PagSeguro payment to work.

    https://github.com/LeonidasBrasileiro/XojoPagSeguro.git

    I have used a webcontrolwrapper for the javascript part and embedded it on a ContainerControl, which also encapsulates everything needed for the payments (credit card data, buyer's data, ...). In order to show the project, I made a shopping cart so people can add products to it and simulate a purchase.

    In order for it to work, it is needed a PagSeguro account. I suggest a 'sandbox ' account, which was what I used, with all configurations made at their portal (email, token, etc.).

    The sample app works but has some flaws I'm working on. Any suggestions/improvements are welcome.

    In order to work, you need to adapt some 'PagSeguro_' constants at the Session object and place an instance of the 'Pagador' control on a page. I think the sample app is good enough to show how it works.

    Next Steps:

    For a real world application, I will remove all the 'Pag_Seguro_' Constants and set them on a separate text file on the server, so they can be loaded as properties whenever a new session starts. I can even (maybe) use a SQLite database to store these values for improved security.

    Another improvement to be made is using a database for handling values stored in the Session.saleitem dictionary.

    I couldn't figure how to solve an annoying issue of the app: It will not allow a new purchase after completing one and going back to the shopping cart page.

    Code and Interface mixes english and portuguese expressions. Sorry for that.

  2. Tim P

    Nov 19 Pre-Release Testers feedback://46303

    HTTP 406 Not Acceptable - The server isn't able to produce a response that you can accept.
    https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406

    This is happening because you are defining the language and charset that you can accept as something other than what the server is willing or able to send.

  3. Leonidas B

    Nov 19 Macaé, RJ, Brazil

    Good to understand.

    Figuring out how to solve that. Already filed a complaint to the supplier. I'm following exactly the 'Accept' parameter explained in the documentation, but keep getting error 406. So frustrating...

    Accept: application/vnd.pagseguro.com.br.v3+json;charset=ISO-8859-1

    or

    Accept: application/vnd.pagseguro.com.br.v3+xml;charset=ISO-8859-1

  4. Rick A

    Nov 19 (Brazil. GMT-3:00)

    Are those lines requested to be there?

    buscador.requestHeaders.AppendHeader("Accept-Language", "utf-8, iso-8859-1;q=0.5, *;q=0.1")
    buscador.requestHeaders.AppendHeader("Accept-Charset", "iso-8859-1")

  5. Rick A

    Nov 19 (Brazil. GMT-3:00)

    Is the communication guaranteed to be coded as iso-8859-1 instead of usual Xojo utf-8 ?

  6. Leonidas B

    Nov 19 Macaé, RJ, Brazil

    @Rick A Is the communication guaranteed to be coded as iso-8859-1 instead of usual Xojo utf-8 ?

    Not sure. This is what the supplier tells about the server side.

  7. Rick A

    Nov 19 (Brazil. GMT-3:00)

    I'm pretty sure this line is malformed:

    buscador.requestHeaders.AppendHeader("Accept-Language", "utf-8, iso-8859-1;q=0.5, *;q=0.1")

    utf and iso are charsets, not languages.

  8. Leonidas B

    Nov 20 Macaé, RJ, Brazil

    I got past the first issue... PagSeguro will return a valid ID at each request!

    I had to change the way the "Sale ID" is fetched. Adapted some PHP code from here: https://github.com/atailton/pagseguro

    Instead of using appID and appKey, I'm using the simpler approach of using email and token to retrieve the ID from PagSeguro.

    Another change is in the Contet-Type, which now is application/x-www-form-urlencoded; charset=ISO-8859-1.

    The method to retrieve an ID from PagSeguro became like this (I cleaned up the code a little bit for clarity):

    Public Sub Get_Sale_ID()
    
    Dim dadosform As New Dictionary
    
    dadosform.Value("email") = "myregisteredemail@pagseguro.com.br"
    dadosform.Value("token") = "my32characterlengthttokenatpagseguro"
    
    Dim buscador As New HTTPSecureSocket
    
    buscador.requestHeaders.DeleteAllHeaders
    buscador.requestHeaders.AppendHeader("Content-Type", "application/x-www-form-urlencoded; charset=ISO-8859-1")
    buscador.Secure = True
    buscador.ConnectionType = HTTPSecureSocket.TLSv1
    
    AddHandler buscador.PageReceived, WeakAddressOf Recebido_Secure
    
    buscador.Post("https://ws.sandbox.pagseguro.uol.com.br/v2/sessions")
    End Sub

    I'm facing another issue now..

    In order for the payment tool to work, it is needed to use some javascript. I chosed to use a webcontrolwrapper to do that.

    I followed the Web Control SDK manual. I have already successfully developed one of these webcontrols by myself previously.

    Unfortunately when I try to run the thing for PagSeguro, I get this javascript error message:

    Could not execute returned javascript: SetSession is not defined
    Source: SetSession('9cc1c88f0e41452b8e3b8ac842ea7762', 'cNrZPj5K');
    Xojo.comm.ajax.begin();

    First parameter is the "Sale ID" I fought for in the first post. Second is the ControlID in the webpage.

    Why it says 'SetSession' is not defined?

    I believe I did it correctly, declaring it on the 'HTMLHeader' Shared Method of the wrapper:

    Public Shared Function HTMLHeader(CurrentSession as WebSession) as String
      If Not IsLibraryRegistered(CurrentSession, JavascriptNamespace, "PagSeguro") Then
        RegisterLibrary(CurrentSession, JavascriptNamespace, "PagSeguro")
        Dim sa() As String
        
        sa.Append "<script src=""https://stc.pagseguro.uol.com.br/pagseguro/api/v2/checkout/pagseguro.directpayment.js""></script>"
        sa.Append "<script>"
        sa.Append a_SetSession
        sa.Append a_GeraIDUsuario
        sa.Append a_BuscaBandeira
        sa.Append a_Parcelamento
        sa.Append a_CriaToken
        sa.Append a_ListaMeiosDisponiveis
        sa.Append "</script>"
        
        Dim kp As String
        kp = Join(sa, EndOfLine.UNIX)
        
        Return join(sa,EndOfLine.UNIX)
        
      End If
    End Function

    a_SetSession, a_GeraIDUsuario, a_BuscaBandeira, a_Parcelamento, a_CriaToken and a_ListaMeiosDisponiveis are constants containing the function definitions. Variable 'kp', used for debugging, aggregates them all and reads like this:

    <script src="https://stc.pagseguro.uol.com.br/pagseguro/api/v2/checkout/pagseguro.directpayment.js"></script>
    <script>
    function SetSession(dado, Controle) {
    	var resultado = new Array(""OK"", dado);
    	Xojo.triggerServerEvent(Controle, 'SetSession', resultado);
    }
    function GeraIDUsuario(Controle) {
    	identificador = PagSeguroDirectPayment.getSenderHash();
        if (identificador != """") {
    		var resultado = new Array(""identificador"", identificador);
    	} else {
    		var resultado = new Array(""FAILED"", ""NULL"");
        }
            Xojo.triggerServerEvent(Controle, 'GeraIDUsuario', resultado);
    }
    function BuscaBandeira(Controle) {
    	var resultado = PagSeguroDirectPayment.getBrand({cardBin : bin});
    	Xojo.triggerServerEvent(Controle, 'BuscaBandeira', resultado);
    }
    function Parcelamento(valor, parc_sem_juros, bandeira, Controle) {
    	var resultado = PagSeguroDirectPayment.getInstallments({
                amount: valor,
                maxInstallmentNoInterest: parc_sem_juros,
        Xojo.triggerServerEvent(Controle, 'Parcelamento', resultado);
    }
    function CriaToken(cardNumber, cvv, expirationMonth, expirationYear, Controle) {
    	var resultado = PagSeguroDirectPayment.createCardToken({
                cardNumber: numCartao,
                cvv: cvvCartao,
                expirationMonth: expiracaoMes,
                expirationYear: expiracaoAno});
            Xojo.triggerServerEvent(Controle, 'CriaToken', resultado);
    }
    function ListaMeiosDisponiveis(valor) {
    	var resultado = PagSeguroDirectPayment.getPaymentMethods({
              amount: valor});
            Xojo.triggerServerEvent(Controle, 'ListaMeiosDisponiveis', resultado);
    }
    </script>

    The Event Definitions required by 'Xojo.triggerServerEvent' are properly defined.

    What am I missing? I can't make sure the javascript is perfect. Is that it? Anything else?

    I'm really interested (and committed to) in finishing this for my own purposes and also to post it as a working solution here or even at github. Maybe I can save someone the hard time (and some fun) I'm having with this...

  9. Leonidas B

    Nov 21 Macaé, RJ, Brazil

    I'm making progress...

    Apparently the issue was here:

    Public Shared Function HTMLHeader(CurrentSession as WebSession) as String
      If Not IsLibraryRegistered(CurrentSession, JavascriptNamespace, "PagSeguroDirectPayment") Then
        RegisterLibrary(CurrentSession, JavascriptNamespace, "PagSeguroDirectPayment")
        Dim sa() As String
        
        sa.Append "<script src=""https://stc.pagseguro.uol.com.br/pagseguro/api/v2/checkout/pagseguro.directpayment.js""></script>"
        sa.Append "<script>"
        sa.Append a_SetSession
        sa.Append a_GeraIDUsuario
        sa.Append a_BuscaBandeira
        sa.Append a_Parcelamento
        sa.Append a_CriaToken
        sa.Append a_ListaMeiosDisponiveis
        sa.Append "</script>"
          
        Return join(sa,EndOfLine.UNIX)
        
      End If
    End Function

    The javascript library name is "PagSeguroDirectPayment" instead of "PagSeguro" as initially posted.

    I'll keep going. As soon as I have a working solution I'll post back.

  10. 2 weeks ago

    Leonidas B

    Nov 27 Answer Macaé, RJ, Brazil

    Hello,

    Here is a first attempt at making this PagSeguro payment to work.

    https://github.com/LeonidasBrasileiro/XojoPagSeguro.git

    I have used a webcontrolwrapper for the javascript part and embedded it on a ContainerControl, which also encapsulates everything needed for the payments (credit card data, buyer's data, ...). In order to show the project, I made a shopping cart so people can add products to it and simulate a purchase.

    In order for it to work, it is needed a PagSeguro account. I suggest a 'sandbox ' account, which was what I used, with all configurations made at their portal (email, token, etc.).

    The sample app works but has some flaws I'm working on. Any suggestions/improvements are welcome.

    In order to work, you need to adapt some 'PagSeguro_' constants at the Session object and place an instance of the 'Pagador' control on a page. I think the sample app is good enough to show how it works.

    Next Steps:

    For a real world application, I will remove all the 'Pag_Seguro_' Constants and set them on a separate text file on the server, so they can be loaded as properties whenever a new session starts. I can even (maybe) use a SQLite database to store these values for improved security.

    Another improvement to be made is using a database for handling values stored in the Session.saleitem dictionary.

    I couldn't figure how to solve an annoying issue of the app: It will not allow a new purchase after completing one and going back to the shopping cart page.

    Code and Interface mixes english and portuguese expressions. Sorry for that.

or Sign Up to reply!