Process Payments

 

On Mobile Card Readers

Now that you've authorized a card and received an encoded payment method, you're ready to process a Card Present Payment.

Partner AppPartner ServerWePay ServerEncoded Payment MethodPOST /paymentsProcess paymentHTTP response (with Payment ID on success)Partner AppPartner ServerWePay Server

General Transaction Flows and Upcoming Changes

FlowCurrent StateFuture StateProgress
Approved auth -
POST /payments results in decline
We return an HTTP 200 and will capture on the backendN/AN/A
RefundsA refund will fail if too much time has elapsed from the capture. The default refund limit is 60 days. We currently return an HTTP 200 with "failure_reason": "unknown".We return an HTTP 400, and identify any retryable refund errors to return HTTP 5XX.Investigation
CancelsCancel requests sent more than 90 minutes after the POST /payments request will result in an HTTP 400 - The payment will need to be captured and then refunded.N/AN/A
TippingWe do not validate the delta in amount between auth and capture. Generally, card networks will decline captures for greater than 120% of the authorization.We will add validation to prevent capture requests with an amount greater than 120% of the authorization. In the meantime, your platform should either alert merchants or implement validation.Planning

Handle Tipping

  • If Amount + Tip is less than to 120% of auth amount, then allow capture
  • If Amount + Tip is greater than or equal to 120% of auth amount, then:
    1. Reverse the initial auth
    2. Obtain a new auth for the total amount (Amount + Tip)

Use the Encoded Payment Method

To create a payment, use the encoded payment method in the payment_method.encoded_payment_method parameter on the POST /payments API request. Be sure to use the value as is, without adding any characters or spaces.
Note

An encoded payment method can only be used once, and every Card Present transaction will need a newly-generated encoded payment method. That said, an encoded payment method will be valid for as long as the authorization. The hold on the cardholder's account will vary depending on the card issuer but the authorization is valid for 7 days.

So far, you should have the following data points to include in your POST /payments request:
  • The merchant's Account ID (this must be the same Account ID used in the authorization function).
  • The currency of the transaction (only USD is currently supported).
  • The encoded payment method (returned by the Card Present SDK).
  • The authorized amount (returned by the Card Present SDK).

Your request thus far would look like the following:

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: {guid}' \
  --data-raw '{
"account_id": "{merchant's-account-id}",
"amount": "{desired-capture-amount}",
"fee_amount": {calculate-processing-and-platform-fees},
"currency”: “USD",
"payment_method": {
	"encoded_payment_method": "{value-from-CP-SDK}""
	}
}'

amount

The amount captured (i.e. the value for the amount parameter in the POST /payments request) should match the amount authorized. In order to capture a different amount, see the Capture Payments section below. Related information on capture scenarios can be found in the Delayed Capture section below as well.

fee_amount

We recommend charging, at minimum, our processing fees in this parameter. Remember that our processing fees are collected from your platform's WePay account, which collects funds based on the fee_amount parameter values on Payments facilitated by your platform.

To do this, find your rates in your contract and use those rates to calculate the processing fee per transaction. If your platform's business model relies on fees per transaction, this would be the place to add those fees in, as well.

Tipping

Tips provided by payers will need to be added to the authorized amount (either by the merchant from physical receipts, or automatically in your app's back end from your UI), and sent to us via the API. To successfully support tipping, use delayed capture to adjust the final amount by sending a request with auto_capture either set to true or not included. Here is an example with it set to true:
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: {guid}' \
  --data-raw '{
    "account_id": "{merchant's-account-id}",
    "amount": "{desired-capture-amount}",
    "currency": "USD",
    "auto_capture": true,
    "payment_method": {
        "encoded_payment_method": "{value-from-CP-SDK}"
    }
}'
Read more about delayed payments below.

Denomination

It is important to note that only newer versions of the Card Present SDK represent amounts in cents, just as the WePay API does.

Card Present SDK versions earlier than 10.0.0-prerelease-5 represent amounts in dollars while the WePay API represents amounts in cents. For instance, $1.00 in the Card Present SDK should be printed as 1.00, and in the API it must be converted to 100.

Handle 500 Errors

After a Card Present authorization returns from the SDK, the payer's portion of the transaction can be considered complete.

That said, it is possible to receive a 500 HTTP error on the subsequent POST /payments request. It is recommended to build out automated retry logic to handle 500's in the Card Present context, but it is up to your platform to design and implement the appropriate retry solution for your use case.

In your design phase, take the following requirements into consideration:

  • Use the same Unique-Key when re-trying a single transaction
  • A single transaction is defined as the same payer, payment method, and purchase content
    • This means that even if the payer comes back 5 minutes later to re-try the payment after you received a 500, the same Unique-Key should be used.

Provide Receipts

If a payer requests a receipt, the merchant must provide one.

For further receipt requirements, see the Card Present receipt guide, and the Card Present card network rules regarding receipts.

Capture Payments

There are two overall methods of capturing payments with an encoded payment method:

Instant Capture

When calling POST /payments, the auto_capture parameter defaults to true even if it's not included in the request. This results in an instant capture of the Payment, which requires tips on receipts to be calculated into the total before calling POST /payments.

Asynchronous Capture

Once a card has been successfully authorized (resulting in an encoded payment method in the Card Present SDK response), a POST /payments does not need to happen right away. Authorizations are generally valid up to 7 days after the in-person transaction, though the exact timeframe depends on the card issuer.

Risks:

  • Auth expiration before a payment can be captured
  • Lost auths due to inadequate logging
To manage the above risks, we recommend capturing payment as soon as possible, and communicating with merchants that payments can never be captured 7 days after the in-person transaction. Additionally, send a POST /payments request immediately after an authorization with the relevant store and forward parameters (described further below), and then capture that payment later to help with logging encoded payment methods.

Here is the high-level asynchronous capture flow:

Partner AppPartner ServerWePay ServerGatewayPayment {id}POST: /payments/{id}/cancelProcess CancellationHTTP Response""Partner AppPartner ServerWePay ServerGateway

The below use cases outline, at a high-level, different methods of implementing asynchronous capture.

Capture a Payment with no changes

  • Capture method: manual or delayed.
  • Manual: Send the POST /payments/{id}/capture request with no JSON body.
  • Delayed: Set the capture_at time in the initial POST /payments API request. The Payment will automatically capture at the designated time.
  • After 90 minutes, a capture is successful for a total equal to the authorization amount. No change in total authorized.

Capture a Payment with a total less than the authorized amount

  • Capture method: partial.
  • Partial: Send the POST /payments/{id}/capture request with the new total in the amounts structure. Be sure to adjust the platform fees so that they do not exceed 20% of the total.
  • After 90 minutes and within 72 hours, a capture is successful for a total less than the authorized amount. The original authorized total is released from cardholder's account. A new authorized total for the lesser total is captured and posted to the cardholder's account.
  • After 72 hours, a new authorization total is not placed against the cardholder's account.

Capture a Payment with a total greater than the authorized amount

  • Capture method: manual or delayed.
  • Manual: Send the POST /payments/{id}/capture request with the new total in the amounts structure. Adjust the platform fees as needed, and keep in mind that they cannot exceed 20% of the total.
  • Delayed: Set the capture_at time in the initial POST /payments request. Before the capture time, send a POST /payments/{id} request to update the amounts on the payment. Adjust fees as needed, and keep in mind that they cannot exceed 20% of the total.
  • After 90 minutes, a capture is successful for a total greater than the authorized amount. No change in total authorized.

High-Level Capture Flows

All capture flows begin with authorizing a card on the mobile card reader.

Manual CaptureDelayed CapturePartial Capture
  • Tip on receipt
  • Call POST /payments with auth amount and auto_capture: false
  • Capture with tip amount added in the amounts JSON block
  • Tip in UI/no tip
  • Call POST /payments with auth amount and auto_capture: false
  • Capture with no changes in the JSON body
  • Call POST /payments with a capture_at value and auto_capture: true (or do not include the auto_capture param).
  • If needed, update Payment prior to capture
  • Payment automatically captures at designated capture_at time
  • Call POST /payments with auto_capture: false
  • Capture with amounts JSON block being less than initial amount
  • Optional: Create the Payment with capture_at and update amount prior to capture, but set auto_capture:true (or exclude the auto_capture param from the request) if using this flow.

Delayed Capture

Use delayed capture to create an API payment which will automatically capture at a designated time up to 7 days from authorization. To create a payment with delayed capture, send a POST /payments API request like this:
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' \
  --data-raw '{
    "account_id": "{merchant's-account-id}",
    "amount": "{desired-capture-amount}",
    "capture_at": {calculate-UNIX-timestamp-within-7-days-of-current-time}
    "fee_amount": {calculate-processing-and-platform-fees},
    "currency”: “USD",
    "payment_method": {
        "encoded_payment_method": "{value-from-CP-SDK}"
    }
}'
For the sake of example, let's say the current date and time when you're sending POST /payments is March 18, 2020 at 3:29:29 PM PST. The farthest out that this payment can be captured would be March 25, 2020 at 3:29:29 PM PST. This means that the maximum UNIX timestamp that you can set as the value for capture_at is 1585175369.

Manual Capture

Manual capture allows a card to be authorized and an API Payment to be created, but the final capture information can be different and the final capture time can be any time within 7 days of authorization.

The final capture amount can be greater than the authorized amount. Capturing an amount less than the authorized amount is considered partial capture. Data related to the payment can be updated, such as Level 2 & Level 3 data and custom_data. Payments using manual capture are typically dependent upon finalized information from the merchant or payer, which is why delayed capture would not be ideal for these payments. Manual capture allows the capture request to be sent as soon as payment details are finalized (i.e. shipping, tip, any changes to amount, or any changes to data), rather than waiting for the capture_at time set in delayed capture.

When creating a payment designated for manual capture, the API request will look like this:

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' \
  --data-raw '{
"account_id": "{merchant's-account-id}",
"amount": "{desired-capture-amount}",
"auto_capture": false,
"fee_amount": {calculate-processing-and-platform-fees},
"currency”: “USD",
"payment_method": {
	"encoded_payment_method": "{value-from-CP-SDK}""
	}
}'
If rBits,the reference_id, or any other data needs to be updated in addition to amounts, do so using a POST /payments/{id} request:
Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments/{id}' \
  -H 'App-Id: {your-app-id}' \
  -H 'App-Token: {your-app-token}' \
  -H 'Api-Version: 3.0' \
  -H 'Content-Type: application/json' \
  --data-raw '{
"reference_id": "{new-reference-id}",
"amounts": {
   "amount": {new-capture-amount},
   "currency": "USD",
   "fee_amount": {fee-amount}
  }
}'
The manual capture can be executed using a POST /payments/{id}/capture request with the amounts and/or custom_data JSON blocks, or with no JSON body.

With a JSON body:

Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments/{id}/capture' \
  -H 'App-Id: {your-app-id}' \
  -H 'App-Token: {your-app-token}' \
  -H 'Api-Version: 3.0' \
  -H 'Content-Type: application/json' \
  --data-raw '{
"amounts": {
  "amount": {new-capture-amount},
  "currency": "USD",
  "fee_amount": {fee-amount}
  }
}'

Without a JSON body:

Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments/{id}/capture' \
  -H 'App-Id: {your-app-id}' \
  -H 'App-Token: {your-app-token}' \
  -H 'Api-Version: 3.0' \
  -H 'Content-Type: application/json' \

Partial Capture

Partial capture is a version of manual capture which allows a card to be authorized and an API Payment to be created, but the final amount in the manual capture request is less than the authorized amount.

To plan for partial capture scenarios, create Payments with a POST /payments request where the auto_capture parameter is set to false. The merchant should then have the option to update the amount for capture for 7 days after the API request. Once the merchant is satisfied, execute a payments/{id}/capture call to finish. Your POST /payments requests when partial capture is an option should look like this:
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' \
  --data-raw '{
    "account_id": "{merchant's-account-id}",
    "amount": "{desired-capture-amount}",
    "auto_capture": false,
    "fee_amount": {calculate-processing-and-platform-fees},
    "currency”: “USD",
    "payment_method": {
        "encoded_payment_method": "{value-from-CP-SDK}""
 }
}'
Alternatively, if you want to protect against expired authorizations before capture, use the delayed capture flow. Set a capture_at time for the Payment within 7 days, and either set auto_capture to true or exclude that parameter from the request. There is no need to call /payments/{id}/capture if you choose this flow.If the merchant opts to partially capture the Payment, then send a POST /payments/{id}/capture request like this:
Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments/{id}/capture' \
  -H 'App-Id: {your-app-id}' \
  -H 'App-Token: {your-app-token}' \
  -H 'Api-Version: 3.0' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "amounts": {
        "amount": {new-capture-amount},
        "currency": "USD",
        "fee_amount": {fee-amount}
    }
}'
Note that the fee_amount parameter is required in the amounts structure, and it must be no greater than 20% of the new capture amount.
Note
POST /payments/{id}/capture requests can only be made once per Payment. For partial capture, this means that you will not be able to later make another request to capture the full authorized amount.

Manage Payment Operations

Partners leveraging our Clear solution must provide merchants with the tools to manage operations after a payment has been created.

Note

Partners leveraging our Link solution can direct merchants to their Chase dashboard for these tools.

Issue Refunds

Refund Card Present payments with the Refund API.
Partner AppPartner ServerWePay ServerGatewayPayment {id}POST: /refundsProcess refundHTTP Response""Partner AppPartner ServerWePay ServerGateway

Note that payments can only be refunded if they were created no more than 60 days prior to the time of refund. If your platform has a custom refund limit, that limit applies here.

For more in-depth guidance, see the Clear developer guide.

Void Payments

Void Card Present payments with the Cancel API.
Partner AppPartner ServerWePay ServerGatewayPayment {id}POST: /payments/{id}/cancelProcess CancellationHTTP Response""Partner AppPartner ServerWePay ServerGateway
Note that payments can only be canceled if they are in a pending state and within 90 minutes of the authorization. After 90 minutes, the authorization will remain on the payer's card until it has expired.In order to construct the cancel API request, provide a UI-input for the merchant to submit the text to be used as the value for the cancel_reason parameter.

Your request may look something like this:

Copy
Copied
curl -X POST \
  --url 'https://stage-api.wepay.com/payments/{id}/cancel' \
  -H 'Accept: application/json' \
  -H 'App-Id: {your-app-id}'\
  -H 'App-Token: {your-app-token}' \
  -H 'Api-Version: 3.0' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "cancel_reason": "item(s) delayed - cannot fulfill order"
}'

A successful response will result in a voided payment.

Warning

Mobile payments can only be canceled within 90 minutes of the authorization.

To effectively release an authorization after an API Payment has been created and past the 90-minute window from authorization, take the following steps:

  1. Call POST /payments/{id} to update the amount value to 100
  2. Call POST /payments/{id}/capture within 72 hours from authorization request
  3. Issue a refund for the remaining dollar with a POST /refunds request

Handle Disputes

Retaining signed receipts for Card Present payments is the best method to challenge any disputes a merchant may receive.

For more in-depth guidance, see the developer guide.

On Terminals and SmartPOS

Now that you've authorized a card and received an encoded payment method, you're ready to process a Card Present Payment.

The iOS SDK now offers SDK Transaction Processing for Terminals, which allows you to create, capture, update, and cancel WePay Payments directly through the SDK instead of the WePay server API. This article walks through the server API flow, and the SDK Transaction Processing feature is outlined in the SDK package documentation. SDK Transaction processing documentation can be accessed by opening the documentation/html/SDK_version/index.html file and finding the following sections of the Integration Guides tab:
  • Integrating the Capture functionality (terminal card readers only)
  • Integrating the Update Deferred Capture functionality (terminal card readers only)
  • Integrating the Cancel Authorization functionality (terminal card readers only)
  • Integrating the Sale functionality (terminal card readers only)
Partner AppCard Present SDKTerminal/Mobile Card ReaderGateway (Process Response)Initiate authAuth response (with encoded payment method on success)Return Response ResultsPartner AppCard Present SDKTerminal/Mobile Card ReaderGateway (Process Response)

General Transaction Flows and Upcoming Changes

FlowCurrent StateFuture StateProgress
Approved offline auth -
POST /payments results in decline
It is possible for the capture of an offline authorization to be declined. This is a risk with accepting offline authorizations.N/AN/A
Approved offline auth -
POST /payments delay in processing
Occasionally, an HTTP 400 with will return on these when there is a delay in processing the auth on our backend. Note that this error can also occur if the request is attempted before the device has come back online.Return an error to indicate steps that should be taken before the POST /payments request is retried.Currently in development
Approved online auth -
POST /payments results in decline
We return an HTTP 200 and will capture on the backendN/AN/A
Refund - Synchronous errorA refund will fail if too much time has elapsed from the capture. The default refund limit is 60 days. We currently return an HTTP 200 with "falure_reason": "unknown".We return an HTTP 400, and identify any retryable refund errors to return HTTP 5XX.Investigation
Refund - Asynchronous errorNote that is it possible for a refund request to result in an HTTP 200, but then asynchronously move to a failed state.N/A.N/A
CancelsPOST /payments/{id}/cancel requests sent more than 90 minutes after the authorization initialized in the SDK will result in an HTTP 400 - The payment will need to be captured and then refunded.N/AN/A
TippingWe do not validate the delta in amount between auth and capture. Generally, card networks will decline captures for greater than 120% of the authorization.We will add validation to prevent capture requests with an amount greater than 120% of the authorization. In the meantime, your platform should either alert merchants or implement validation.Planning

Handle Tipping

  • If Amount + Tip is less than 120% of auth amount, then allow capture
  • If Amount + Tip is greater than or equal to 120% of auth amount, then:
    1. Reverse the initial auth
    2. Obtain a new auth for the total amount (Amount + Tip)

Create a Payment

To create a payment, use the encoded payment method in the payment_method.encoded_payment_method parameter on the POST /payments API request. Be sure to use the value as is, without adding any characters or spaces.
Note

An encoded payment method can only be used once, and every Card Present transaction will need a newly-generated encoded payment method. That said, an encoded payment method will be valid for as long as the authorization. This amount of time will vary depending on the card issuer, but it will generally be 7 days.

So far, you should have the following data points to include in your POST /payments request:
  • The merchant's Account ID (this must be the same Account ID which owns the Terminal).
  • The currency of the transaction (only USD is currently supported).
  • The encoded payment method (returned by the Card Present SDK).
  • The authorized amount (returned by the Card Present SDK).

Your request thus far would look like the following:

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: {guid}' \
  --data-raw '{
"account_id": "{merchant's-account-id}",
"amount": "{desired-capture-amount}",
"fee_amount": {calculate-processing-and-platform-fees},
"currency”: “USD",
"payment_method": {
	"encoded_payment_method": "{value-from-CP-SDK}""
	}
}'

amount

The amount captured (i.e. the value for the amount parameter in the POST /payments request) should match the amount authorized. In order to capture a different amount, see the Capture Payments section below. Related information on capture scenarios can be found in the Delayed Capture section below as well.

fee_amount

We recommend charging, at minimum, our processing fees in this parameter. Remember that our processing fees are collected from your platform's WePay account, which collects funds based on the fee_amount parameter values on Payments facilitated by your platform.

To do this, find your rates in your contract and use those rates to calculate the processing fee per transaction. If your platform's business model relies on fees per transaction, this would be the place to add those fees in, as well.

Tipping

Tips provided on the receipt will need to be added to the total by the merchant and submitted to your platform via your merchant UI. This means that you should build a check specifically for terminals with tip.mode set to prompt_on_receipt, and use deferred capture to adjust the amount once the merchant has submitted tip amounts at the end of the day.

Tips provided on the terminal are included in the amount parameter of the authorization info object in the auth response from the Card Present SDK.

Denomination

It is important to note that the Card Present SDK represents amounts in dollars while the Payments API represents amounts in cents. For instance, $1.00 in the Card Present SDK should be printed as 1.00, and in the API it should be printed as 100.

Handle 500 Errors

After a Card Present authorization returns from the SDK, the payer's portion of the transaction can be considered complete.

That said, it is possible to receive a 500 HTTP error on the subsequent POST /payments request. It is recommended to build out automated retry logic to handle 500's in the Card Present context, but it is up to your platform to design and implement the appropriate retry solution for your use case.

In your design phase, take the following requirements into consideration:

  • Use the same Unique-Key when re-trying a single transaction
  • A single transaction is defined as the same payer, payment method, and purchase content
    • This means that even if the payer comes back 5 minutes later to re-try the payment after you received a 500, the same Unique-Key should be used.

Print Receipts

On the Verifone V400m terminal, merchants can print receipts from the device. Identify terminals with printer capabilities by examining the available printer flag in the Card Present SDK.

Verifone V400m terminals display an option for merchants to print a receipt after a successful authorization. If this option is selected, run the print receipt function in the Card Present SDK.

For further receipt requirements, see the Card Present receipt guide, and the Card Present card network rules regarding receipts.

Signatures must be collected in the following cases:

  • NFC/contactless transaction
  • Keyed entry transaction

Additionally, merchants are encouraged to collect signature on receipt if they accept tip, and/or if they wish to validate the terms of sale (such as "all sales final").