A payment intent represents an intended money movement for an EBT transaction. Your server creates a
payment intent with the amount and fulfillment details, then the mobile SDK collects the customer’s
PIN to authorize it.
Payment intents expire after one hour. Create them close to the time of checkout.
Payment flow
Tender types
EBT payments support two tender types:
| Tender type | Description |
|---|
SNAP | Supplemental Nutrition Assistance Program benefits. Only SNAP-eligible items qualify. |
EBT_CASH | EBT cash benefits. Covers a broader range of items. |
Each payment intent covers a single tender type. To split a payment across SNAP and EBT cash, create
separate payment intents for each.
Fulfillment types
Every payment intent requires a fulfillment type and address:
| Fulfillment type | Description |
|---|
DELIVERY | Benny delivers the order to the customer. |
PICKUP | The customer picks up the order. |
The fulfillmentAddress must include address1, city, state, and postalCode.
Create a payment intent
Call POST /v1/payment/intent from your server to create a new payment intent.
Request
| Field | Type | Required | Description |
|---|
amount | integer | Yes | Amount in cents. |
tenderType | string | Yes | SNAP or EBT_CASH. |
fulfillmentType | string | Yes | DELIVERY or PICKUP. |
fulfillmentAddress | object | Yes | The delivery or pickup address. |
paymentMethodId | string | Yes | The payment method to charge. |
externalUserId | string | Yes | Your identifier for the customer. |
orderId | string | No | Your identifier for the order. |
Response
| Field | Type | Description |
|---|
paymentIntentId | string | Pass this to the mobile SDK to authorize the payment. |
Node.js
Python
Kotlin
Java
const intent = await client.payment.createIntent({
amount: 2500,
tenderType: "SNAP",
fulfillmentType: "DELIVERY",
fulfillmentAddress: {
address1: "123 Main St",
city: "New York",
state: "NY",
postalCode: "10001",
},
paymentMethodId: "pm_12345",
externalUserId: "user_12345",
orderId: "order_67890",
});
// Pass intent.paymentIntentId to the mobile app
console.log(intent.paymentIntentId);
intent = client.payment.create_intent(
amount=2500,
tender_type="SNAP",
fulfillment_type="DELIVERY",
fulfillment_address={
"address1": "123 Main St",
"city": "New York",
"state": "NY",
"postal_code": "10001",
},
payment_method_id="pm_12345",
external_user_id="user_12345",
order_id="order_67890",
)
# Pass intent.payment_intent_id to the mobile app
print(intent.payment_intent_id)
val intent = client.payment().createIntent(
PaymentCreateIntentParams.builder()
.amount(2500)
.tenderType("SNAP")
.fulfillmentType("DELIVERY")
.fulfillmentAddress(
PaymentCreateIntentParams.FulfillmentAddress.builder()
.address1("123 Main St")
.city("New York")
.state("NY")
.postalCode("10001")
.build()
)
.paymentMethodId("pm_12345")
.externalUserId("user_12345")
.orderId("order_67890")
.build()
)
// Pass intent.paymentIntentId() to the mobile app
println(intent.paymentIntentId())
var intent = client.payment().createIntent(
PaymentCreateIntentParams.builder()
.amount(2500)
.tenderType("SNAP")
.fulfillmentType("DELIVERY")
.fulfillmentAddress(
PaymentCreateIntentParams.FulfillmentAddress.builder()
.address1("123 Main St")
.city("New York")
.state("NY")
.postalCode("10001")
.build()
)
.paymentMethodId("pm_12345")
.externalUserId("user_12345")
.orderId("order_67890")
.build()
);
// Pass intent.paymentIntentId() to the mobile app
System.out.println(intent.paymentIntentId());
Authorize the payment
Once your mobile app receives the paymentIntentId, use the PinInput component to collect the
customer’s PIN and submit the payment.
val controller = rememberPinInputController(sessionToken = sessionToken)
PinInput(
controller = controller,
onSuccess = { ebtResult ->
when (ebtResult) {
is EbtResult.Payment -> {
// Payment authorized
}
else -> {}
}
},
)
Button(onClick = {
controller.submit(
panTokenId = panTokenId,
operation = EbtOperation.Payment(paymentIntentId = "pi_xxx"),
)
}) {
Text("Pay")
}
@StateObject private var controller = PinInputController(sessionToken: sessionToken)
PinInput(
controller: controller,
onSuccess: { ebtResult in
switch onEnum(of: ebtResult) {
case .payment:
// Payment authorized
break
default:
break
}
}
)
Button("Pay") {
controller.submit(
panTokenId: panTokenId,
operation: EbtOperation.Payment(paymentIntentId: "pi_xxx")
)
}
For the complete component API, see the Android SDK or
iOS SDK reference.
Update a payment intent
Call PATCH /v1/payment/intent to update the fulfillment details of a pending payment intent. You can
only change the fulfillment type and address.
Request
| Field | Type | Required | Description |
|---|
paymentIntentId | string | Yes | The payment intent to update. |
fulfillmentType | string | Yes | DELIVERY or PICKUP. |
fulfillmentAddress | object | Yes | The updated address. |
Node.js
Python
Kotlin
Java
await client.payment.updateIntent({
paymentIntentId: "pi_xxx",
fulfillmentType: "PICKUP",
fulfillmentAddress: {
address1: "456 Oak Ave",
city: "Brooklyn",
state: "NY",
postalCode: "11201",
},
});
client.payment.update_intent(
payment_intent_id="pi_xxx",
fulfillment_type="PICKUP",
fulfillment_address={
"address1": "456 Oak Ave",
"city": "Brooklyn",
"state": "NY",
"postal_code": "11201",
},
)
client.payment().updateIntent(
PaymentUpdateIntentParams.builder()
.paymentIntentId("pi_xxx")
.fulfillmentType("PICKUP")
.fulfillmentAddress(
PaymentUpdateIntentParams.FulfillmentAddress.builder()
.address1("456 Oak Ave")
.city("Brooklyn")
.state("NY")
.postalCode("11201")
.build()
)
.build()
)
client.payment().updateIntent(
PaymentUpdateIntentParams.builder()
.paymentIntentId("pi_xxx")
.fulfillmentType("PICKUP")
.fulfillmentAddress(
PaymentUpdateIntentParams.FulfillmentAddress.builder()
.address1("456 Oak Ave")
.city("Brooklyn")
.state("NY")
.postalCode("11201")
.build()
)
.build()
);
Delete a payment intent
Call DELETE /v1/payment/intent to cancel a pending payment intent. You can only delete intents that
haven’t yet gone through authorization.
Node.js
Python
Kotlin
Java
await client.payment.deleteIntent("pi_xxx");
client.payment.delete_intent("pi_xxx")
client.payment().deleteIntent("pi_xxx")
client.payment().deleteIntent("pi_xxx");
Balance checks
You can check a customer’s EBT balance without creating a payment intent. Use the PinInput
component with EbtOperation.BalanceCheck:
controller.submit(
panTokenId = panTokenId,
operation = EbtOperation.BalanceCheck,
)
controller.submit(
panTokenId: panTokenId,
operation: EbtOperation.BalanceCheck()
)
The onSuccess callback receives an EbtResult.Balance with SNAP and EBT cash balances in cents.