Create Payment Methods

Tokenize Credit Cards

For this section, we implement the Card on File:

  • Create a Payment Method by calling /payment_methods (via Tokenization), which contains the payer's credit card or payment bank.
  • Store the payment method ID for the user.
  • When a payer is ready to buy, create a Payment by calling /payments, using the payment method ID.

For testing purposes in the stage environment, use the credit card values listed in the testing section here.

First, we create a Payment Method.

Copy
Copied
WePay.tokens.create({
  "resource": "payment_methods",
  "payment_methods": {
    "type": "credit_card",
    "credit_card": {
      "card_number": "4111111111111111", // Visa test number.
      "expiration_month": 4,
      "expiration_year": 2023,
      "cvv": "007",
      "virtual_terminal_mode": "web",
      "auto_update": false
    }
  }
}, {}, function(response) {
  console.log(response);
});
The response contains various information, including a token, which looks something like payment_methods-f4059a38-5640-41f3-a426-ef915eacaefa.
Note

Tokens have a time-to-live (TTL) of 30 minutes.

Once you have a payment method, a successful $0 authorization must occur before you can use that payment method to create a payment. The $0 auth occurs automatically when the trigger_verification parameter is set to true (default) on the WePay.tokens.create JS call. Successful authorizations are reflected when the Payment Method has "status": "verified".

Note: trigger_verification defaults to true, and we strongly discourage sending a false value. Checking the validity of a credit card upon submission offers the payer a chance to submit a different, valid payment method while they are still in your UI, in addition to reducing the number of unsuccessful payments overall.

You can either immediately create a Payment, or you can create a Payment Method and process Payments at a later time.


Designate Or Identify A Card's Funding Source

BETA

Disabling the creation of debit or credit card payment methods is currently a closed BETA offering on API version 3.1.rc.1.3.

We offer a method of allowing only a credit or debit card funding source during payment method creation. Alternatively, you can simply read the value on the payment method after creation to identify its funding source.

Designate A Funding Source

When creating a new payment method with POST /payment_method or POST /payments, you can set the optional field card_funding to debit or credit. The debit value will only successfully create a payment method if the card's funding source is debit, while the credit value will only successfully create a payment method if the card's funding source is credit.
Test credentials

In our stage environment, use the following test credentials:

  • 4242424242424242 for credit
  • 4000056655665556 for debit

Your request may look like this:

debitcreditJS
Copy
Copied
{
  "type": "credit_card",
  "credit_card": {
    "card_holder": {
      "holder_name": "John Doe",
      "address": {
        "postal_code": "94122",
        "country": "US"
      }
    },
    "card_number": "4000056655665556",
    "expiration_month": 1,
    "expiration_year": 2042,
    "cvv": "007",
    "card_on_file": false,
    "recurring": false,
    "card_funding": "debit"
  }
}
Copy
Copied
{
  "type": "credit_card",
  "credit_card": {
    "card_holder": {
      "holder_name": "John Doe",
      "address": {
        "postal_code": "94122",
        "country": "US"
      }
    },
    "card_number": "4242424242424242",
    "expiration_month": 1,
    "expiration_year": 2042,
    "cvv": "007",
    "card_on_file": false,
    "recurring": false,
    "card_funding": "credit"
  }
}
Copy
Copied
WePay.tokens.create({
  "resource": "payment_methods",
  "payment_methods": {
    "type": "credit_card",
    "credit_card": {
      "card_number": "4111111111111111", // Visa test number.
      "expiration_month": 4,
      "expiration_year": 2023,
      "cvv": "007",
      "virtual_terminal_mode": "web",
      "auto_update": false,
      "card_funding": {"credit / debit"}
    }
  }
}, {}, function(response) {
  console.log(response);
});
Reminder: This is an optional field. If card_funding is not specified in your API request, the default value will be null and this will allow a payment_method_id to be created regardless of the card's funding source.Identify A Funding Source

Once a card has been created, you can identify its funding source on the card_funding response parameter even if you did not set the parameter during creation. Note that the value can be null, but this is a rare edge case that will only occur on very new card types / offerings that have not yet been incorporated in our bin lookup sources.

Disable Prepaid/Gift Card Payment Methods

BETA

Disabling the creation of prepaid card payment methods is currently a closed BETA offering on API version 3.1.rc.1.3.

We offer you a way to ensure that payment methods aren't being created with prepaid type cards including but not limited to: gift cards, reloadable, virtual, etc.

When creating a new payment method with POST /payment_method or POST /payments, you can set the optional field bin_details.is_prepaid to false, indicating that you do not want a payment_method_id to be created if we validate that the card information submitted is a prepaid type card.

Below is an example request:

inlinetokenized
Copy
Copied
{
  "type": "credit_card",
  "credit_card": {
    "card_holder": {
      "holder_name": "John Doe",
      "address": {
        "postal_code": "94122",
        "country": "US"
      }
    },
    "card_number": "5496198584584769",
    "expiration_month": 1,
    "expiration_year": 2042,
    "cvv": "007",
    "card_on_file": false,
    "recurring": false,
    "bin_details": {
      "is_prepaid": false
    }
  }
}
Copy
Copied
WePay.tokens.create({
  "resource": "payment_methods",
  "payment_methods": {
    "type": "credit_card",
    "credit_card": {
      "card_number": "4111111111111111", // Visa test number.
      "expiration_month": 4,
      "expiration_year": 2023,
      "cvv": "007",
      "virtual_terminal_mode": "web",
      "auto_update": false,
      "bin_details": {
        "is_prepaid": false
      }
    }
  }
}, {}, function(response) {
  console.log(response);
});
If you set is_prepaid to false and prepaid card information is sent, the error PREPAID_VALIDATION_MISMATCH will be returned and a payment_method_id will not be created to make payments.

Reminder: This is an optional field. If is_prepaid is not specified in your API request, the default value will be null and this will allow a payment_method_id to be created regardless if it is a prepaid card or not.
Note
If is_prepaid is set to true, a payment_method_id will be created for prepaid type cards only.

Tokenize Bank Accounts

Note

Only banks in the US can be used as payment methods.

This flow allows your platform to provide a custom UI for processing ACH payments. We highly recommend tokenizing raw bank account data even though it does not fall within the scope of PCI requirements. As a reminder, ACH payments are only supported for US Banks.

First, tokenize the payment_bank_us structure of a Payment Method:
Copy
Copied
WePay.tokens.create({
  "resource": "payment_methods",
  "payment_methods": {
    "type": "payment_bank_us",
    "payment_bank_us": {
      "account_holder": {
        "holder_name": "Test Test",
        "email": "foo@bar.com",
        "address": {
          "country": "US",
          "postal_code": "94025"
        }
      },
      "account_number": "124523092", // Use any 3-17 digit bank account number for testing.
      "routing_number": "021000021", // Testing US routing number
      "account_type": "checking"
    }
  }
}, {}, function(response) {
  console.log(response);
});
Store the token from the response.

Next, either:

  1. create a Payment immediately with the token ID, or
  2. create a Payment Method
Note
When a payment method is created using POST /payment_methods, the last_four variable that is returned will be the last four numbers of the bank account. However, if you have verified your account via Plaid, this might be the last four numbers of your tokenized bank account number (TAN).

Create A Bank Account Payment With The Token ID

Use the token parameter on the POST /payments request:
Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments' \
  -H 'App-Id: {your-app-id}'\
  -H 'App-Token: {your-app-token}'\
  -H 'Api-Version: 3.0'\
  -H 'Content-Type: application/json'\
  -H 'Unique-Key: {generate-a-unique-key}' \
  --data-raw '{
    "account_id": "{merchant-account-id}",
	  "amount": 20000,
	  "currency": "USD",
	  "fee_amount": 100,
    "payment_method": {
      "type": "bank_account_us",
      "token": {
        "id": "{payment_methods-TOKEN-HERE}"
        },
    },
    "custom_data": {
      "my_key": "invoice #54321"
      },
    "rbits": [{
      "properties": {
        "report_url": "example.com"
        },
        "receive_time": 1367958263,
        "source": "guidestar",
        "type": "business_report"
      }]
    }'

Create A Bank Account Payment Method With The Token ID

Use the token parameter on the POST /payment_methods request:
Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payment_methods' \
  -H 'App-Id: {your-app-id}'\
  -H 'App-Token: {your-app-token}'\
  -H 'Api-Version: 3.0'\
  -H 'Content-Type: application/json'\
  -H 'Unique-Key: {generate-a-unique-key}' \
  --data-raw '{
  "token": {
    "id": "{payment_methods-YOUR-TOKEN-HERE}"
  },
  "custom_data": {
    "my_key": "invoice #54321"
  },
  "rbits": [{
    "properties": {
      "report_url": "example.com"
    },
    "receive_time": 1367958263,
    "source": "guidestar",
    "type": "business_report"
  }]
}'
Note the Unique-Key header, described in our Standard Headers and Idempotency article. This header is required when calling POST /payments and POST /refunds in order to protect against duplicate processing, and is recommended on all other endpoints.

You'll notice that the API response will send "status": "unverified. To move the status to verified, the payer will need to verify the micro deposit amounts that we send to the bank account.

To verify a payment bank, you are responsible for:

  1. Collecting acceptance of WePay's Terms of Service and NACHA rules from the payer
  2. Handling the micro deposit verification flow with the payer

To handle the micro deposit verification flow, first build out a UI to accept two dollar amounts in cents from the payer. Next, build out an email flow through which the payer can access that UI and submit the micro deposit amounts. Once the payer submits those amounts, make a POST /payment_methods/{id}/verify_bank_deposits call using the payment method ID in the endpoint and the amounts sent to your account holder by the payer in the JSON request body:

Copy
Copied
{
  "microdeposits": [10, 55]
}
On a success, the API response will send "status": "verified". Once a payment bank is in a verified status, you can use it in POST /payments calls to process ACH payments.

On the second failed verification attempt, the payment method object will have a status of disabled. Subsequent requests to POST /payment_methods/{id}/verify_bank_deposits after 2 failed attempts will return the following error:
Copy
Copied
{
  "error_code": "INVALID_PARAMS",
  "error_message": "Invalid parameter(s).",
  "details": [{
    "target": ["payment_methods"],
    "target_type": "HTTP_REQUEST_PATH",
    "reason_code": "ID_NOT_FOUND",
    "message": "ID 00000000-6261-5553-0000-00000003557c not found."
  }]
}
Additionally, the payment_methods.microdeposit_verification_failed Notification event topic will fire. If a payment was created prior to verification failure, it will move from a status of pending to canceled. Payments with a bank account payment method pending verification can stay in a pending state for 30 days before they will automatically move to canceled.

The constraint of only 2 verification attempts exists to protect against fraud in the ACH/Echeck sphere. If this occurs, the payer should double check their bank account credentials and resubmit payment. To this end, send a DELETE /payment_methods/{id} request to remove the abandoned Payment Method.

By default, ACH payments take 2 business days (excluding weekends and US holidays) to complete processing and be available to the merchant in a completed status. This window typically allows the issuing bank to process the request and send a response back to us. If the response from an issuing bank declines the payment and takes longer than 2 business days, then the payment will automatically be refunded.

Inline Payment Methods

When creating inline payment methods in a POST /payments request, the authorization minimum is $1, include that in the amount in the payment. There will be a $1 pending charge that will drop off in 7 days or if the payment is canceled before that.