Set up payment extensions

Ask about this Page
Copy for LLM
View as Markdown

Learn how to integrate with payment providers.

Payment extensions allow you to connect InStore to your payment providers. Use the information below to set up connections for credit cards, stored-value cards, digital wallet, and pay on account.

About asynchronous payment processing

InStore supports asynchronous payment processing, which allows you to process payments of uncertain duration. When a payment is initiated, InStore sends a request to the payment extension endpoint in your Integration Server. From the perspective of the API, your Integration Server acts as the "client." Your Integration Server should respond to InStore with a "200" acknowledgment response and pass the request on to your payment provider.
Instead of relying on a standard request-response pattern, respond to the initial request with a 200 acknowledgment and continue the payment flow asynchronously.
The request body includes two InStore-generated URLs: statusUrl, which you can use to send intermediate updates and client messages, and callbackUrl, which you use to send the final payment result. As your payment provider returns updates during processing, your Integration Server can forward that information to InStore by calling these URLs. You can optionally display the updates for users to see throughout the payment process, for example as stepper messages. For some payment types, you can include prompts to collect additional information from the user.

At the end of processing, use the callback URL to send the payment provider's final result, which is whether the payment was successful or failed.

In contrast, the composable tender extension payment type is processed directly within the user interface rather than through a backend API call. See Composable tender extension.

Prepare to receive requests from InStore

Details of setting up a custom extension and verifying the signature may vary depending on the programming language, framework, and server setup you are using.

To set up a payment extension, do the following:

  1. Set up endpoints on your integration server to receive the payment extension data. You need to create a script or program that listens for incoming requests at a specific URL and supports all endpoints defined for the payment type of the particular extension. You can do this using a variety of programming languages and frameworks, depending on your server setup. InStore sends HTTP POST and GET requests to the URL you specify.

  2. Make sure your endpoints can handle the request format used by each action. POST actions use JSON-formatted request and response bodies. GET actions use route or query parameters, as documented for that action.

  3. Configure all endpoints to verify the HMAC-SHA256 signature that InStore sends with each request. This signature is a security measure that ensures the data being sent to your endpoint is actually coming from InStore and has not been tampered with in transit.

  4. To verify the signature, you'll need to perform the following steps:

    1. Extract the signature from the incoming proxy request headers. The header key for the signature is X-Signature.
    2. Compute an HMAC-SHA256 hash over the JSON-stringified request payload, using the apiKey value that you configured for the extension in the InStore Center.
    3. Compare the generated hash to the signature included in the incoming request headers. If they match, the data has not been tampered with and can be safely processed by your endpoint.
    4. Once you've verified the signature, you can process the incoming data as needed. This may involve storing it in a database, triggering other actions in your system, or sending a 200 response back to acknowledge receipt of the request.
  5. Review the header information, shared request fields, and processor webhook paths below. Ensure that your endpoints are set up to receive and process this data correctly.

  6. View the section Send InStore the final result of an asynchronous payment to see the specific data that your payment provider must send back to InStore via the callback URL. Ensure that your payment provider is prepared to return this data in the correct format.

The API key is a symmetric secret, not an asymmetric private key. Both InStore and your extension must hold the same key.

Header information that you receive in all InStore payment requests

NamePurpose
X-SignatureSends a hash that verifies the current payload value with the API key assigned to the payment processor.
X-Correlation-IdSends an identifier to track the process from all applications: InStore Core, InStore API, and the webhook service.
X-Transaction-IdSends an identifier to track the full checkout transaction from all applications: InStore Core, InStore API, and the webhook service.
X-API-KeySends a key to authenticate the InStore API call to the payment processor service.

Fields that you receive in all InStore payment requests

FieldPurpose
payload_urlIdentifies the services to call and always matches the webhook URL payload.
payloadSends the request data, which varies with the payment process type.
verification_signatureSends a hash that verifies the authenticity of the request. This serves to sign the current payload value with the API key that was assigned to the payment processor.
tenant_idIdentifies the tenant that is being called.
requestIdIdentifies the current process.
callbackUrlSpecifies the webhook service you call to send the messages to InStore.
statusUrlSpecifies the webhook service you call to update status and send messages to the client.

Processor webhook paths that we provide for specific payment types

Payment TypeProcessor Webhook PathPurpose
BankCardinitialize_credit_processorRequests that your service initialize the payment provider.
connect_card_readerRequests that your service connect to the credit reader.
capture_paymentRequests the capture of payment. Only applies if the provider supports payment capture before collecting payment.
collect_credit_paymentRequests the collection of the payment through a pin entry device (PED).
create_credit_refundRequests a credit refund.
cancel_credit_paymentRequests that your service cancel a previous credit payment request.
user_responseSends information that was provided by the user.
GiftCardstoredvaluecardRequests the creation of a new stored-value card payment.
storedvaluecard_processSends instructions for processing this stored-value card's information.
Walletinitialize_walletRequests the processing of a digital wallet payment.
pay_walletSends information for processing this wallet payment.
cancel_walletRequests that your service cancel the wallet payment.
refund_walletRequests a refund for the wallet payment.
Pay on Account (POA)pay_on_accountRequests the processing of a pay-on-account payment.
payonaccount/processSends instructions for processing this POA payment's information.
payonaccount/create_accountRequests that your service create an account record for this pay-on-account payment.
payonaccountlogDirects your Integration Server to log information about this pay-on-account payment.

Respond asynchronously to InStore requests

InStore stops accepting messages and updates after receiving the final result of the payment process.

Use the status callback to send updates during an asynchronous payment

You can choose to send updates back to InStore using the statusUrl callback.

Use this callback to send optional messages and other updates:

/webhook/payment/:requestId/status

Send intermediate messages and updates to InStore

Messaging is available for all payment types as described in Customize payment stepper messages. To send messages, include the following body in the status callback:
{
  message: string
  severity: string
  properties?: object
}

Where

FieldPurpose
messageThe content of the message to display to the user. For example, "Processing payment...".
severityThe importance of the message, which can be Info, Warning, or Error. InStore uses this value to determine how to display the message.
propertiesAn optional object that contains any additional information that the retailer can use with downstream processing.

Add user prompts during payment processing

Prompts that require user input during payment are available for select payment types, specifically:

  • payments of type Credit
  • the redeem action for stored-value card payments. No prompts are available for the stored-value card number-retrieval action.
Use the status callback. See Send user prompts.

Dynamically replace the timeout for an asynchronous payment

You can use the status callback to dynamically replace the default timeout by specifying a different value in the keepAliveMs field within a message block. Use this body:
{
  "message": "Common.messages.authorizingCard",
  "severity": "Info",
  "keepAliveMs": 10000
}
In this example, the keepAliveMs field is set to 10000 milliseconds (10 seconds).
Another way to control timeouts is to specify them in the payment processor for the payment method.

Send InStore the final result of an asynchronous payment

The final result of the payment process is sent to InStore using the callback URL. The callback path is the same for all asynchronous payment types, but the payload varies by payment type. Depending on the payment type, the response can use different field names and status values.

After InStore receives the final callback payload, no further updates are accepted.

Use this callback path to send the final result of the payment process:

/webhook/payment/:requestId

Many payment types use a payload shape similar to the following:

{
  result: string
  data?: object
  method?: string
}

Where:

FieldPurpose
resultIndicates the final status for payment types that use the result field. Supported values vary by payment type.
dataContains payment-type-specific response fields. Some payment types return those fields at the top level instead of inside data.
methodIs the value that your payment service uses to identify the payment method. If not specified in your result, InStore assigns the method from the payment processor payload.

Review the examples for your payment type and return the payload shape documented for that payment type.

Sample credit result

Use a payload shape similar to the following when you return the result of the collect_credit_payment request through the callback URL:
Processor webhook path: collect_credit_payment
{
  result: Success | Failed
  data: {
    cartKey: "123e4567-e89b-12d3-a456-426614174000"
    processor: "Brand-X Debit Card"
    processor_id: "213121111"
    last4: "4242"
    brand: "visa"
    account_type: "credit"
    application_preferred_name: null
    dedicated_file_name: null
    authorization_response_code: "3030"
    application_cryptogram: null
    terminal_verification_results: null
    transaction_status_information: null
    amount: {
      amount: 123
      currency: "USD"
      precision: 2
      timestamp: "2024-06-02T14:20:55.488Z"
    }
  }
}

Where

AttributeTypeDescription
cartKeyStringUnique identifier for the cart, which was generated by InStore.
processorStringThe label that represents this payment method in the Total area of the payment page.
processor_idStringThe identifier for the payment processor that was used for the transaction.
last4StringLast four digits of the credit card number.
brandStringBrand of the credit card.
account_typeStringType of card account, such as credit or debit.
application_preferred_nameStringCardholder's name as displayed on their credit or debit card.
dedicated_file_nameStringIdentifier used by the card issuer.
authorization_response_codeStringCode that indicates the status of the transaction request sent to the card issuer.
application_cryptogramStringDigital signature generated by the card’s embedded chip.
terminal_verification_resultsStringSeries of bits set by the PED for deciding how to respond to the request for payment.
transaction_status_informationStringStatus of the transaction, which is returned by the card issuer.
amountObjectAmount object that contains the following fields: amount, currency, precision, timestamp

Sample stored-value inquiry result and redemption result

You can use the following payload shapes for the two parts of a stored-value transaction. The first part returns the card information for storedvaluecard/{cardNumber}, and the second part returns the payment result for storedvaluecard_process.
Processor webhook path: storedvaluecard/{cardNumber}
{
  result?: "Success" | "Failed"
  balance?: { amount: number, currency: string, precision: number }
  cardType?: string
  issuer?: string
  number?: string
  pinRequired?: boolean
  reason?: string
}
Processor webhook path: storedvaluecard_process
Action: Redeem
{
  result?: "Success" | "Failed"
  reason?: string
  balance?: { amount: number, currency: string, precision: number }
  number?: string
  issuer?: string
  method?: string
  transaction_id?: string
  payment_id?: string
}

Where:

AttributeTypeDescription
numberStringIdentifies the stored-value card number that is being redeemed or whose validity is being checked.
resultStringIndicates the status of the card information retrieval or redemption attempt. Value can be Success or Failed.
balanceObjectProvides the current balance amount, currency, and precision.
cardTypeStringRetailer's configuration for card type.
issuerStringRetailer's configuration for issuer.
pinRequiredBooleanIf true, InStore prompts the user for a PIN during the transaction.
reasonStringRetailer's configuration for supporting information. For example, this could be an error code for a result of Failed.
methodStringThe payment method used for the transaction.
transaction_idStringIdentifier returned by the payment provider for the transaction.
payment_idStringIdentifier returned by the payment provider for the payment.

Sample pay-on-account result

You can use the following payload shape when you return the result of the payonaccount/process request through the callback URL.
Processor webhook path: payonaccount/process
{
  status: succeeded | failed
  reason?: string
  balance: { amount: number, currency: string, precision: number }
  credit_limit: { amount: number, currency: string, precision: number }
  account_number: string
  company_name: string
  authorized_user_id?: string
  transaction_id: string
  payment_id: string
  method: string
}

Where the following are the fields that InStore uses:

AttributeTypeDescription
statusStringIndicates the result of the pay-on-account payment attempt. Value can be succeeded or failed.
transaction_idStringThe transaction ID that will be passed to Composable Commerce.
payment_idStringThe payment servicer's identifier for this payment.
methodStringThe payment method used for the transaction.

Sample wallet result

You can use the following payload shape when you return the result of the pay_wallet request through the callback URL.
Processor webhook path: pay_wallet
{
  code?: string
  result: string
  error_message?: string
  transaction_id?: string
  merchant_id?: string
  terminal_id?: string
  method?: string
  total?: number
}

Where

AttributeTypeDescription
codeStringApplies only when the result is "failed". Options are "A2" (timeout) or "A7" (declined).
resultStringIndicates the result of the wallet payment attempt. Value can be "success" or "failed".

Sample cancel wallet request and result

Use the following payload shape for cancel_wallet:
{
  transactionId: "dc3bcf40-b8dc-4ad6-a6df-fb7733a3ca67"
  paymentProcessorId: "6a0453a27d9e46013347f552"
  requestId: "c2ef250c-32c7-4ea6-8c70-a715c579b6e1"
}
Use the requestId from the earlier pay_wallet process as the transactionId.

Expected result shape:

{
  result: "success"
  error_message: ""
  code: "00"
  timestamp: "2026-06-02T14:20:55.488Z"
}
InStore checks only the result field in the success response.
The following is a failure result shape for the pay_wallet cancel request:
{
  code: "A10"
  error_message: "Payment Cancel"
  result: "failed"
  timestamp: "2026-06-02T14:20:58.811Z"
}
Use any code value except A2 or A7 in the failure response.