Activating customers via API


(Spencer Hunter) #4

HI @sunlightmedia, is the Id you’re POSTing to a Customer ID or a Beneficial Owner Id? Those are separate resources in the API and will have their own unique identifier.


#5

We used the customer ID. Below are the steps we took. Please let us know where we went wrong.

  1. Create LLC Business account

URL = https://api-sandbox.dwolla.com/customers/cc7c1e33-1fc7-4a2a-85ca-9058e6658668

  1. Create Beneficial owners

URL = https://api-sandbox.dwolla.com/beneficial-owners/33fd7053-ae6f-4656-a8fe-2436131a5e23

  1. Create bank account

  2. Micro deposit verified.

  3. All Account status’ are verified and No action needed

We have created a transaction and the amount is reflected in the Dwolla account

07%20AM

But Send Fees to Admin ( main merchant ) is not reflected:

'fees'=>[
  '_links'=> [
  'charge-to'=> [
  'href'=> 'https://api-sandbox.dwolla.com/funding-sources/bfbcaaf8-42ad-4137-a4b6-2e7f25e3b3cc'],
  ]
  'amount'=> [
  'value'=>0.5 ,'currency'=>"USD"
  ]
],

(Spencer Hunter) #6

@sunlightmedia, it looks like the only thing that you’ll want to update on your end is the charge-to href. This will want to be a pointer to the Customer URL that identifies the user account you wish to assume the fee. i.e.

'fees'=>[
  '_links'=> [
  'charge-to'=> [
  'href'=> 'https://api-sandbox.dwolla.com/customers/cc7c1e33-1fc7-4a2a-85ca-9058e6658668'],
  ]
  'amount'=> [
  'value'=>0.5 ,'currency'=>"USD"
  ]
]

#7

@spencer We have set the fees charge-to href with the seller’s customer url http://api-sandbox.dwolla.com/customers/cc7c1e33-1fc7-4a2a-85ca-9058e6658668. But it is not showing the fees for the transaction where the main transaction is displayed. There should be 2 transactions – one with $0.50 (Fees) and another with $95.00 (main), but here we can only see the main transaction. Admin fees are not displayed. Our client would like to earn a commission per each transaction. Is this possible?

18%20AM

{  
	"_links":{
		"source":{
			"href":"https://api-sandbox.dwolla.com/funding-sources/bfbcaaf8-42ad-4137-a4b6-2e7f25e3b3cc"
		},
		"destination":{
			"href":"https://api-sandbox.dwolla.com\funding-sources/669175eb-ee3f-44e9-94ed-60e1e4311995"
		}
	},
	"amount":{
		"currency":"USD",
		"value":0.95
	},
	"fees":{
		"_links":{
			"charge-to":{
				"href":"http://api-sandbox.dwolla.com/customers/cc7c1e33-1fc7-4a2a-85ca-9058e6658668"
            },
            "amount":{
            	"value":0.05,
            	"currency":"USD"
            }
        },
        "metadata":{
        	"paymentId":"KHTJ1SKFHP0",
        	"note":"payment for #KHTJ1SKFHP0"
        },
        "clearing":{
        	"destination":"next-available"
        },
        "correlationId":"f9barivgnku6pka18tbjgvv387"
}

(Spencer Hunter) #8

Hi @sunlightmedia, The intent of the facilitator fee as it exists today is for you as the application to collect a fee from a portion of the transaction that your app facilitates. In this scenario you are facilitating transactions between two different users. If user A sends $0.95 and is being charged a fee of $0.05 then they should see $1 debited from their bank account. When that $1 settles and is marked as processed in the Dwolla system, you as the application (facilitator) will receive $0.05 and the recipient will receive the remaining $0.95. We don’t currently support sending the fee to an account that is different than the Master account that is building the app to facilitate transactions between users.


#9

Hi @spencer we’re not entirely clearly on this. What would be in the charge-to href field in this case? We did not find any customer ID for the Master Account. The main payment was $1 and it should send 0.95 to seller and 0.5 to the master Dwolla account.

"_links":{
	"source":{
		"href":"THIS IS THE BUYER FUNDING SOURCE LINK"
	},
	"destination":{
		"href":"THIS IS THE SELLER'S FUNDING SOURCE LINK"
		}
	},
	"amount":{
		"currency":"USD",
		"value":0.95
	},
	"fees":{
		"_links":{
		"charge-to":{
			"href":"WHAT IS THE MASTER CUSTOMER LINK? OR HERE WILL BE SELLER FUNDING SOURCE OR SELLERS CUSTOMER LINK? OR BUYER CUSTOMER LINK/FUNDING SOURCE LINK"
		}
	},
	"amount":{
		"value":0.05,
		"currency":"USD"
		}
	},

(Spencer Hunter) #10

Hi @sunlightmedia, If the Buyer (source) is being charged the fee in the transaction then it’ll be a link to the Customer resource that represents that buyer. i.e. https://api-sandbox.dwolla.com/customers/cc7c1e33-1fc7-4a2a-85ca-9058e6658668

Here’s an example:

$transfer = $transfersApi->create([
  '_links' => [
    'source' => [
      'href' => 'https://api-sandbox.dwolla.com/funding-sources/c91d6516-1855-4d36-be7c-bc78cc7c52c3',
    ],
    'destination' => [
      'href' => 'https://api-sandbox.dwolla.com/funding-sources/ae245cd4-ee55-4d20-8bad-a24642c9473f'
    ]
  ],
  'amount' => [
    'currency' => 'USD',
    'value' => '22.00'
  ],
  'fees' => [
    [
     '_links' => [
           'charge-to'=>[
              'href'=> 'https://api-sandbox.dwolla.com/customers/089cd9b4-fb5a-449e-a90e-30ffd83bbb9b'
            ]
        ],
        'amount' => [
             'value' => '2.00', // fee
              'currency' => 'USD'
           ]
    ]]
]);

#11

@spencer Does that mean that the source href = buyer’s funding source, and destination href = seller’s funding source, and fees charged to href link will be buyer’s account link?. If so, that’s how we currently have it set up.

EG: Buyer purchased a $1 product, so $0.95 will be sent to the seller and $0.05 will be sent to the main admin.


(Spencer Hunter) #12

@sunlightmedia, Yep, that’s correct!


#13

@spencer One issue we’re having is that transactions are occurring, but the fees are not listed in the Dwolla account transaction list in the Merchant account. Only the seller transactions are visible.


(Spencer Hunter) #14

@sunlightmedia, The issue might be how you’re passing in the Fees request param. It’s an array of Fee Objects which looks something like this:

{
"_links": {
    "source": {
        "href": "https://api-sandbox.dwolla.com/funding-sources/{{VCRBalanceFundingSourceId}}"
    },
    "destination": {
        "href": "https://api-sandbox.dwolla.com/funding-sources/{{CRFundingSourceId}}"
    }
},
"amount": {
    "currency": "USD",
    "value": "42.00"
},
"metadata": {
    "foo": "bar"
},
"fees": [
    {  
       "_links":{  
          "charge-to":{  
             "href":"https://api-sandbox.dwolla.com/customers/{{CRCustomerId}}"
          }
       },
       "amount":{  
          "value":"2.00",
          "currency":"USD"
       }
    }
]    

}

Can you share some of your code where you’re specifying Fees to confirm these are being passed in properly? If they aren’t we’ll ignore them and create the transaction without fees.


#15

Hi @spencer, transaction without fees are working fine. We’ll just need to provide the admin merchant a commission of 5-10%. That’s why we’ve added fees. Below is some sample code:

include('../dwolla/vendor/autoload.php'); 
$curl = curl_init();
	curl_setopt($curl, CURLOPT_URL,DWOLLA_POST_URL_TOKEN);  
	curl_setopt($curl, CURLOPT_FAILONERROR, true);
	curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
	 
	 $postData = array(
	 	'client_id' => DWOLLA_CLIENT_ID,
	 	'client_secret' => DWOLLA_CLIENT_SECRET,
	 	'grant_type' => 'client_credentials'
	 );
	 curl_setopt($curl, CURLOPT_POST, true);
	 curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
	 curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/x-www-form-urlencoded' )); // send JSON and expect JSON
	 
	//// Timeout in seconds
	 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
	 curl_setopt($curl, CURLOPT_TIMEOUT, 60);
	//// Dont verify SSL certificate (eg. self-signed cert in testsystem)
	 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
	 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	 $output = curl_exec($curl);
	if ($output === FALSE) {
		echo 'An error has occurred: ' . curl_error($curl) . PHP_EOL;
	}
	else {
		$output = json_decode($output) ;
		
		$token = $output->access_token;
	}
	
	DwollaSwagger\Configuration::$access_token = $token;
	DwollaSwagger\Configuration::$debug = 1;
	$apiClient = new DwollaSwagger\ApiClient(DWOLLA_API_CLIENT); 
	
	$transfersApi = new DwollaSwagger\TransfersApi($apiClient);
	$transfer = $transfersApi->create([
	  '_links' => [
	    'source' => [
	      'href' => $general_func->get_field_value(TBL_PREFIX. "user", "dwallo_funding_source", "user_id", $user_id) // Buyer funding source
	    ],
	    'destination' => [
	      'href' => $general_func->get_field_value(TBL_PREFIX. "user", "dwallo_funding_source", "user_id", $seller_id) // Seller funding source

	    ]
	  ],
	  'amount' => [
	    'currency' => 'USD',
	    'value' => '0.95'
	  ],
	  'fees' =>[
		   
		    '_links' => [
		      'charge-to' => [
		      'href' => $general_func->get_field_value(TBL_PREFIX. "user", "dwallo_account", "user_id", $user_id) // Buyer account URl

		      ]
		      ],
		    'amount' => [
		      'value' => 0.05,
		      'currency' => "USD"
		    ]
		   
		],
	  'metadata' => [
	    'paymentId' => $invoice,
	    'note' => 'payment for #'.$invoice,
	  ],
	  'clearing' => [
	    'destination' => 'next-available'
	  ],
	  'correlationId' => session_id()
	]);

 echo '<pre>'.print_r($post,true).'</pre>';  

#16

Hi @spencer, just following up on this


(Spencer Hunter) #17

@sunlightmedia, it looks like your fees array is missing an extra set of brackets.

'fees' => [
[
 '_links' => [
       'charge-to'=>[
          'href'=> 'https://api-sandbox.dwolla.com/customers/089cd9b4-fb5a-449e-a90e-30ffd83bbb9b'
        ]
    ],
    'amount' => [
         'value' => '2.00', // commission
          'currency' => 'USD'
       ]
]]

#18

Thank you, @spencer – this is working now.

The only remaining issue we have is related to document uploads. We’ve tried to upload PDFs and JPEG files, but are receiving an error.

$target_url =  'https://api-sandbox.dwolla.com/customers/83a44d27-ddfa-4b72-8d80-d34546a46a78/documents';
  $file_name_with_full_path =  '/documents/sample.jpg' ;  
  $post = array('documentType' => 'passport','file'=>'@'.$file_name_with_full_path); 
  $ch = curl_init();
  $headers = array(
    'Content-type: multipart/form-data',
    'Authorization: Bearer '. $token,
    'Accept: application/vnd.dwolla.v1.hal+json',
); 
  curl_setopt($ch, CURLOPT_URL,$target_url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_POST,1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

  $result = json_decode(curl_exec($ch));
   
 
  echo '<pre>'.print_r($result,true).'</pre>';

ERROR
stdClass Object
(
    [code] => ValidationError
    [message] => Validation error(s) present. See embedded errors list for more details.
    [_embedded] => stdClass Object
        (
            [errors] => Array
                (
                    [0] => stdClass Object
                        (
                            [code] => Invalid
                            [message] => Invalid file type.
                            [path] => /file
                            [_links] => stdClass Object
                                (
                                )

                        )

                )

        )

)

#19

Hi @spencer, just following up on this


(Shreya Thapa) #20

Hi @sunlightmedia!

The curl handle in this line of your code seems to be inconsistent with the ones above it. Perhaps try changing that to:

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

When you are specifying the path for the file you are trying to upload, using the PHP realpath() function is a good practice, as it returns the canonicalized absolute pathname.

Furthermore, @spencer recommends using Guzzle, an easy-to-use PHP HTTP client library which has a simple interface for POSTing requests. They have a very well documented manual here. There is an abundance of resources on the internet on how to upload files using Guzzle.

Please let us know if the error persists; we would be glad to help you resolve it!


#21

Hi @shreya, we made the suggested changes and tried using Guzzle the but the realpath function is not working. It’s returning blank.

<?php 

echo echo realpath("/documents/11_053234_sample-usa-passport.jpg");
 
?>

The above code isn’t working but the file exists: https://www.rx-post.com/documents/11_053234_sample-usa-passport.jpg

After using Guzzle, we got the following error:

Client error: `POST https://api-sandbox.dwolla.com/customers/7a2b38f2-08b2-4587-baac-094b6990ac90/documents` resulted in a `400 Bad Request` response:
{"code":"BadRequest","message":"The request body contains bad syntax or is incomplete."} 
{"code":"BadRequest","message":"The request body contains bad syntax or is incomplete."}

Below is the code we’re using:

include("vendor/autoload.php");
  $client = new \GuzzleHttp\Client();  
  $file_name_with_full_path = "/home/rxpost/public_html/documents/11_231701_sample-usa-passport.jpg"
 Try {
            $response = $client->post(
                "https://api-sandbox.dwolla.com/customers/7a2b38f2-08b2-4587-baac-094b6990ac90/documents", [
                    'headers' => [
                        'Accept'                => 'application/vnd.dwolla.v1.hal+json',
                        'Content-Type'          => 'multipart/form-data',  // <-- commented out this line
                        'Authorization'         => 'Bearer '. $token,
                    ],
                    'multipart' => [
                        [
					        'name'     => 'documentType',
					        'contents' => 'passport'
					    ],
                        [
                            'name'     => 'file',
                            'contents' => fopen($file_name_with_full_path, 'r') ,
                            'filename' => "my-passport.jpg"                        ] 
                    ],
                ] 
            );
           echo $response->getBody()->getContents();
        } catch(\Exception $e) {
            echo $e->getMessage();
            $response = $e->getResponse();
            $responseBody = $response->getBody()->getContents();

            echo $responseBody;
            exit;
        }

(Shreya Thapa) #22

Hi @sunlightmedia, thank you for applying the changes, and getting back to us. It seems you can omit realpath() if you are using Guzzle.

The response is referring to a syntax error in your code. I checked the Guzzle documentation for sending form files, and found that this may have something to do with how you are POSTing the data,

According to the documentation, your POST request should look something like this,

$response = $client->request(‘POST’, ‘https://api-sandbox.dwolla.com/customers/7a2b38f2-08b2-4587-baac-094b6990ac90/documents’, […

Please let us know if the code works after referring to the official documentation.


#23

Hi @shreya

We have removed the realpath, but the same issue happens. The error is saying that “The request body contains bad syntax or is incomplete”. We also find the same error after adding that.

Both are doing same job ($client->post or $client->request(‘POST’ ). As you we haven’t been able to find any PHP-based documentation about “document upload”, we need your help regarding this. Below is our code. We did not find any issue, but the document is not uploaded.

$file_name_with_full_path = realpath($_SERVER['DOCUMENT_ROOT'].'/documents/'.$img_path)  ;
   
  include("vendor/autoload.php");
  $client = new \GuzzleHttp\Client();  
   
 Try {
            $response = $client->request('POST',
                'https://api-sandbox.dwolla.com/customers/7a2b38f2-08b2-4587-baac-094b6990ac90/documents', [
                    'headers' => [
                        'Accept'                => 'application/vnd.dwolla.v1.hal+json',
                        'Content-Type'          => 'multipart/form-data',  // <-- commented out this line
                        'Authorization'         => 'Bearer '. $token,
                    ],
                    'multipart' => [
                        [
					        'name'     => 'documentType',
					        'contents' => 'passport'
					    ],
                        [
                            'name'     => 'file',
                            'contents' => fopen($file_name_with_full_path, 'r') ,
                            'filename' => $img_path
                        ] 
                    ] 
                ] 
            );
           echo $response->getBody()->getContents();
        } catch(\Exception $e) {
            echo $e->getMessage();
            $response = $e->getResponse();
            $responseBody = $response->getBody()->getContents();

           echo '<pre>'. print_r($responseBody,true);
            exit;
        }
        
Error : {"code":"BadRequest","message":"The request body contains bad syntax or is incomplete."}
Online Documentation

Creating Transfers in PHP using Guzzle