Charge
The charge flow is the ability to charge credit cards from the back office, by adding your application's Payment Processing Page inside the inTandem UI as an iFrame.
Embedding your Payment Processing Page
inTandem embeds your Payment Processing Page iFrame inside the Charge window by requesting the iFrame page from GET {REDIRECT_URI}/charge?pivot_id={PIVOT_ID}.
As you can see, we'll also append a "pivot_id" query param to the {redirect_uri}/charge route ,so you can identify the business when the iFrame loads.
Charge events
Interacting with the iFrame is done via JavaScript postMessage.
Once the user places all the required information inside the iFrame (card number, expiration dates, etc.) and clicks the Charge button, inTandem will emit a JavaScript postMessage with the following data message object:
{
type: 'generic',
func: 'getToken',
params: {
amount: number,
save_card: boolean,
pivot_id: string, // same as business_uid
client_id: string,
currency: string
}
}In return, we are expecting a token. This token will be used throughout the payment process to identify the transaction.
const messageObj = {
type: 'generic',
token: {TOKEN}
}
window.parent.postMessage(messageObj, '*');Charge postMessage
Here's an example of how you can listen to the Charge postMessage event and send back a token
window.addEventListener(
'message',
(event) => {
if (event.data.type === 'generic' && event.data.func === 'getToken') {
// Do some credit card number validations
const cardValidationErrors = validateCard(); // Can be a function that returns an array of errors
// if card validations checks error
if (cardValidationErrors.length > 0) {
const messageObj = {
type: 'generic',
func: 'validationFailure'
}
window.parent.postMessage(messageObj, '*')
// present the errors in the iFrame
return;
// If the card checks correctly with no issues
} else {
const token = {TOKEN}
const messageObj = {
type: 'generic',
token: {TOKEN}
}
window.parent.postMessage(messageObj, '*');
// Store token and payment details in your database for later reference
return;
}
}
}
)Card on file (saved payment methods)
When a client pays with a payment method already saved for them, inTandem does not open a checkout session and does not embed your payment page. There is no postMessage exchange and the end user is never redirected.
Instead, inTandem calls POST /charge directly, server to server, using the card token and customer_id stored from the original save-card call. The result is read synchronously from your response - there is no checkout webhook for this flow, and the Thank You page and redirect steps described below do not apply.
The request body is the same as for a new card; only the origin of token and customer_id differs.
POST /charge
inTandem sends a POST request to your application's /charge endpoint in two cases:
- New card - Backoffice - once the token is received from the postMessage exchange described above.
- Saved card - Client portal checkout & back office - directly, with no embedded page and no token exchange. See Card on file above.
Once the token is received, inTandem sends a POST request to your application's {redirect_uri}/charge, containing the transaction details:
POST {redirect_uri}/charge
{
"amount": 10.60,
"currency": "USD",
"token": "addtkthQ16trAsldSar50v6sLfdmuQ",
"description": "30 minutes phone call",
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7",
"initiator": "client",
"payment_status_uid": "9pplnrdnf6cq0iqb",
"fees": [
{ "type": "surcharge_fee", "amount": 0.60 }
]
}| Property | Type | Description |
|---|---|---|
| token | string | The "token" in the request payload corresponds to the token you initially passed in the postMessage from the iFrame |
| customer_id | string | customer_id will only be provided if a card was saved during the session. See below "Card on file" section |
| initiator | "business" | "client" | Indicates the origin of the Charge. "business" - when the charge is initiated from the back office by the business. "client" - when the charge was initiated from the client portal when payment was made using a saved card (meaning that the end-user was never redirected to the external checkout page) |
| amount | number | Total amount to charge, in the given currency. Includes any fee sent in fees. |
| currency | string | ISO 4217 currency code, e.g. USD. |
| description | string | Description of what is being paid for. |
| payment_status_uid | string | inTandem payment identifier. Omitted for charges not linked to a payment record. |
| fees | array of objects | Offset fee applied to this payment. At most one item. Provided only when initiator is client. The top-level amount already includes the fee - do not add it on top. See Fee object below. |
Fee object
| Property | Type | Description |
|---|---|---|
| type | enum | "surcharge_fee" | "convenience_fee"The kind of offset fee applied. Always sent in this exact lowercase form |
| amount | number | The fee amount, in the charge currency. Already included in the top-level amount |
- A charge carries at most one fee, and never both types - a business can enable only one.
surcharge_feeapplies to credit cards only. If the funding type is not credit, it won't be sent.- The fee amount is validated against the business's configured settings before the request is sent, so there is no need to recompute or reject it.
- inTandem displays these fees as "Surcharge" and "Convenience fee" in its own interface and reports. Those are display labels only and never appear in the API payload.
Your app processes the payment with the payment gateway, and upon successful payment, you'll respond with a charge_key value:
{
"charge_key": "DzlrBcilbnvBd48gca8um3AkNHoj85"
}The Charge flow ends when we are successfully receiving the charge_key value.
Thank You page
This applies to the back-office embedded flow only. A saved-card charge has no dialog and no success page - the outcome is taken from your /charge response. The payment dialog closes and a success page will be displayed.

Failed transactions
Upon transaction failure, you can send an error response (instead of ‘charge_key’) with the error message to be presented to the user.
{
"error": "ERROR MESSAGE",
"error_data": {
"message": "error_message"
}
}
Payment errorserror: error message to be displayed in the payment dialog.
error_data.message: the error message that will be displayed in the payment page when viewing the payment from the Payments page.
Updated 8 days ago
