Server to Server Integration

 

There may be cases when using tokenization is not compatible with your front-end, and you have the necessary PCI, security, and privacy infrastructure to handle sensitive material like raw credit cards and PII. In these cases, your platform should work directly with your relationship executive or integration team to build out a Server to Server Integration.

If your platform is approved for a server to server integration with WePay, follow this guide for handling PCI and PII data without the WePay JavaScript.

Note

You’ll need an SAQ-D to qualify for this integration. Find out more in our Security Certification.

This guide is a supplement to the Basic Integration guides, providing context and how-to’s relevant to a Server to Server Integration and replacing the following sections of the Basic Integration:

Although ACH payments handle data which does not technically fall under the scope of PCI requirements, WePay highly recommends handling raw bank account information with the same care as raw credit card information.


 

When onboarding merchants, your platform must create a WePay API legal entity object associated with that merchant, which contains sensititve PII data. If your platform is prepared to handle raw PII data according to WePay’s Security Certification, and your platform has been approved for a Server to Server Integration by WePay, then use the following method rather than the tokenization version of Create a Legal Entity.

Legal Note

Each time KYC information for Controller(s) or Beneficial Owner(s) is submitted to or edited in your platform, the following disclaimer must be displayed to the user:

By clicking “Submit,” you hereby certify, to the best of your knowledge, that the information provided above is complete and correct.

Variations of the text above can be used, so long as the variance does not significantly change the meaning.

Your UI must also provide the controller with a review of the details submitted by other entity beneficial owners. The date_of_brith and either social_security_number for US or social_insurance_number for Canada, should not be displayed. Instead use a GET /legal_entities/{id} call to retrieve the boolean values for date_of_birth_is_present and either social_security_number_is_present or social_insurance_number_is_present.

Find out more in our CIP and KYC Certification guide.

Step 1: Generate WePay Risk Headers

Load the WePay JS in your UI where the end-user triggers the POST /legal_entities request to WePay. On this specific page, load the JS 5 seconds after page-load in order to generate the WePay-Risk-Token and Client-IP. Call WePay.risk.get_risk_token() which will return the WePay-Risk-Token; retrieve the Client-IP from the WePay-Risk-Token object.

Pass these to your server.

Now that you have the items needed for the required WePay risk headers, attatch them to the POST /legal_entities request.

Instead of using the Javascript library to tokenize PII data associated with a legal entity, simply send a POST to the Legal Entity endpoint, using a similar structure:

curl -X POST \
 /legal_entities \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "additional_representatives": {
    "representative_0": {
      "is_beneficial_owner": true,
      "name": {
        "first": "Duff",
        "last": "Bar"
      },
      "phone": {
        "country_code": "+1",
        "phone_number": "5558883333"
      },
      "date_of_birth": {
        "year": 1989,
        "month": 12,
        "day": 17
      },
      "address": {
        "line1": "742 Evergreen Terrace",
        "city": "Springfield",
        "postal_code": "58008",
        "region": "ND",
        "country": "US"
      },
      "email": "example@example.com",
        "personal_country_info": {
        "US": {
          "social_security_number": "321-01-2345"
        }
      }
    }
  },
  "address": {
    "line1": "123 Fake Street",
    "city": "San Francisco",
    "postal_code": "94101",
    "region": "CA",
    "country": "US"
  },
  "controller": {
    "is_beneficial_owner": false,
    "name": {
      "first": "Foo",
      "last": "Bar"
    },
    "job_title": "CFO",
    "phone": {
      "country_code": "+1",
      "phone_number": "5556667777"
    },
    "date_of_birth": {
      "year": 1900,
      "month": 1,
      "day": 1
    },
    "address": {
      "line1": "456 Nocturn Alley",
      "city": "Beverly Hills",
      "postal_code": "90210",
      "region": "CA",
      "country": "US"
    },
    "email": "example@example.com",
    "personal_country_info": {
      "US": {
        "social_security_number": "012-34-5678"
      }
    }
  },
  "country": "US",
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "description": "The Foo Bar Charity is very important.",
  "entity_country_info": {
    "US": {
      "employer_identification_number": "123211230",
      "legal_form": "nonprofit_corporation"
    }
  },
  "entity_name": "Foo Bar Charity",
  "phone": {
    "country_code": "+1",
    "phone_number": "5556667777"
  },
  "primary_url": "http://www.example.com",
  "terms_of_service": {
    "acceptance_time": 1490656130,
    "original_ip": "12.37.161.213"
  }
}'

WePay will return the legal entity ID in the API response.

Back to Basics

Next up: Basic Integration Onboard Merchants to continue building out the onboarding flow.


Process Credit Card Payments

 

If you opt to collect raw credit card information (and accept higher PCI scope), you can execute payments using an inline payment method, or you can create a payment method in one request and execute a payment in a second request.

Both methods require WePay risk headers. Load the WePay JS in your UI where the end-user triggers the POST /payment_methods and/or POST /payments requests.

Method 1: Inline

Essentially, you can send a POST /payments request to WePay like so:

curl -X POST \
 /payments \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "account_id": "fc7066a1-a0b8-424a-af1b-231182e3dbc6",
  "amount": 1000,
  "auto_capture": true,
  "currency": "USD",
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "fee_amount": 30,
  "initiated_by": "customer",
  "order_id": "c2e8decd-b9e1-47ca-bd25-e1f5aff7272e",
  "payment_method": {
    "type": "credit_card",
    "credit_card": {
      "auto_update": false
      "card_holder": {
        "holder_name": "Jon Snow",
        "email": "example@wepay.com",
        "address": {
          "line1": "123 Fake Street",
          "city": "Redwood City",
          "region": "CA",
          "country": "US",
          "postal_code": "94025"
        }
      },
      "card_number": "4111111111111111",
      "card_on_file": false,
      "cvv": "007",
      "expiration_month": 4,
      "expiration_year": 2030,
      "recurring": false
    }
  },
  "reference_id": "072429987420"
}'

Method 2: Payment Method → Payment

Essentially, you can send a POST /payment_methods request to WePay like so:

curl -X POST \
 /payment_methods \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "credit_card": {
    "auto_update": false,
    "card_holder": {
      "address": {
        "country": "US",
        "postal_code": "94025"
      },
      "email":"example@wepay.com",
      "holder_name": "Jon Snow"
    },
    "card_number": "5496198584584769",
    "card_on_file": false,
    "cvv":"007",
    "expiration_month": 4,
    "expiration_year": 2020,
    "recurring": false,
    "virtual_terminal_mode": "mobile",
    "trigger_verification": true
  },
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "rbits": [{
    "properties": {
      "report_url": "example.com"
    },
    "receive_time": 1367958263,
    "source": "guidestar",
    "type": "business_report"
  }],
  "type": "credit_card"
}'

From here, use the payment method ID to execute a payment:

 /paymemts \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "account_id": "fc7066a1-a0b8-424a-af1b-231182e3dbc6",
  "amount": 1000,
  "auto_capture": true,
  "currency": "USD",
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "fee_amount": 30,
  "initiated_by": "customer",
  "order_id": "c2e8decd-b9e1-47ca-bd25-e1f5aff7272e",
  "payment_method": {
    "type": "payment_method_id",
    "payment_method_id": "61bbc106-6581-4a40-be2e-a874fe6d7539" // Use the payment method ID from the POST /payment_method requet
      },
  "reference_id": "072429987420"
}'

Note that POST /payments requests using payment method IDs do not require WePay risk headers if they are not dirctly triggered by the user (i.e. automatic recurring payments).

Back to Basics

Next up: the next section if your integration includes ACH payment processing, or the Basic Integration Process Payments article for additional payment functions.


Process ACH Payments

 

Unlike credit card payments, ACH payments require the two-step method where you’ll first creat a payment method and then create a payment. Note that a second request is required after the payment method but before a payment is created. This will be a POST /payment_methods/{id}/verify_bank_deposits request once the payer has received the micro deposits in order to verify the bank account as a valid payment method.

Step 1: Create A Payment Method

Send a POST /payment_methods request to WePay:

curl -X POST \
 /payment_methods \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "type": "payment_bank_us",
  "payment_bank_us": {
    "account_number": "124523092",
    "account_type": "checking",
    "routing_number": "021000021",
    "account_holder": {
      "holder_name": "Foo Bar",
      "email": "example@wepay.com",
      "address": {
        "country": "US",
        "postal_code": "94025"
      },
      "phone": {
        "country_code": "+1",
        "phone_number": "5556667777"
      }
    }
  }

Store the payment method ID from the API response for future use. Note that the payment method status will be unverified.

Step 2: Verify A Payment Method

When a payment bank is created as a payment method, WePay will automatically send 2 micro deposits to that bank account. The payer must identify those two micro deposit amounts and submit them in order to verify the payment method. Your platform will need to provide a UI for this process. Once the payer submits the micro deposit amounts to your platform, you will forward them to WePay with a POST /payment_methods/{id}/verify_bank_deposits request:

curl -X POST \
 /payment_methods/{id}/verify_bank_deposits \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "microdeposits":[10, 55]  // Send the amounts submitted by the payer
}'

If these amounts match the micro deposits sent, the API response will show that the payment method status is verified.

If these amounts do not match the micro deposits sent, the API response will show that the payment method status is unverified.

Note

WePay allows 2 verification attempts where the amounts do not match the micro deposits sent. On the 3rd incorrect attempt, WePay Support must be enlisted in order to verify the payment method.

Step 3: Create A Payment

Once a payment bank’s status is verified, it can be used in a POST /payments request. If the end user is not directly triggering the payment (i.e. if the POST /payments request is queued but waiting for the verified payment method status), then WePay risk headers are not required.

curl -X POST \
 /paymemts \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
  "account_id": "fc7066a1-a0b8-424a-af1b-231182e3dbc6",
  "amount": 1000,
  "auto_capture": true,
  "currency": "USD",
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "fee_amount": 30,
  "initiated_by": "customer",
  "order_id": "c2e8decd-b9e1-47ca-bd25-e1f5aff7272e",
  "payment_method": {
    "type": "payment_method_id",
    "payment_method_id": "61bbc106-6581-4a40-be2e-a874fe6d7539" // Use the payment method ID from the POST /payment_method request
      },
  "reference_id": "072429987420"
}'

Note that POST /payments requests using payment method IDs do not require WePay risk headers if they are not dirctly triggered by the user (i.e. automatic recurring payments).

Back to Basics

Next up: Basic Integration Process Payments article for additional payment functions.


Create a Payout Method

 

In order for your merchants to receive the funds collected in their WePay account, their payouts must be enabled. This involves verifying legal entity information in addition to creating their payout method.

If you are comfortable collecting bank payout information, you can simply call the payout_methods endpoint directly with all information after generating the WePay Risk Token.

Step 1: Generate WePay Risk Headers

Load the WePay JS in your UI where the end-user triggers the POST /payout_methods request to WePay. On this specific page, load the JS 5 seconds after page-load in order to generate the WePay-Risk-Token and Client-IP. Call WePay.risk.get_risk_token() which will return the WePay-Risk-Token; retrieve the Client-IP from the WePay-Risk-Token object.

Step 2: Create A Payout Method

Now that you have the items needed for the required WePay risk headers, attatch them to the POST /payout_methods request.

Instead of using the Javascript library to tokenize the bank account data, simply send a POST to the payout methods endpoint:

curl -X POST \
 /payout_methods \
 -H "App-Id: 121212" \
 -H "App-Token: prod_MTAwXzk5OWIwZT666LWYwNWItNDU4MS1iZjBiL" \
 -H "Api-Version: 3.0" \
 -H "Content-Type: application/json" \
 -H "WePay-Risk-Token: 123e4567-e89b-12d3-a456-426655440000" \  // Insert the token returned by the WePay JS
 -H "Client-IP: 100.166.99.123" \  // Insert the IP returned by the WePay JS
 -d '{
	"legal_entity_id": "YOUR-LEGAL-ENTITY-ID", // Use the legal entity ID associated with the merchant
	"nickname": "Test Payout Acct",
	"type": "payout_bank_us",
    	"payout_bank_us": {
    		"account_number": "12345678",
		"routing_number": "021000021",
		"account_type": "checking"
	}
}

Back to Basics

Next up: Basic Integration Payout Merchants article for next steps once you have the payout_method_id


Test and Launch

 

Your testing and development for a Server to Server integration, be sure to follow the Basic Integration Test and Launch guidelines.