I’m working on a point-of-sale system and need to connect a Stripe physical reader. Below is my JavaScript implementation for initializing the reader and managing its discovery process.
// Initialize Stripe Terminal
const stripeTerminal = StripeTerminal.create({
onFetchConnectionToken: async () => {
try {
const response = await fetch("http://localhost:8000/get_connection_token/", { method: 'POST' });
if (!response.ok) {
throw new Error("Unable to retrieve connection token");
}
const { secret } = await response.json();
return secret;
} catch (error) {
console.error("Connection token retrieval error:", error);
throw error;
}
},
onUnexpectedReaderDisconnect: () => {
console.error("Reader lost connection unexpectedly.");
alert("The reader has disconnected unexpectedly. Please check the connection and try again.");
},
});
console.log("Stripe Terminal ready to use.");
// Discover available readers
async function findReaders() {
try {
console.log("Searching for readers...");
const options = {
simulated: false,
location: "LOCATION_ID"
};
const discoverResult = await stripeTerminal.discoverReaders(options);
console.log("Reader Discovery Result:", discoverResult);
if (discoverResult.error) {
console.error('Discovery error:', discoverResult.error.message);
alert('Error during reader discovery. Please check your network setup.');
return null;
}
if (discoverResult.discoveredReaders.length === 0) {
console.warn("No readers found. Ensure the device is powered on and properly connected.");
alert("No reader found. Check connectivity and configuration settings.");
return null;
}
console.log("Found readers:", discoverResult.discoveredReaders);
alert("Readers successfully discovered.");
return discoverResult.discoveredReaders[0];
} catch (error) {
console.error("Error during reader discovery:", error);
alert("An unexpected issue occurred while discovering readers.");
return null;
}
}
// Connect to a chosen reader
async function linkReader(reader) {
try {
console.log("Connecting to reader:", reader.label);
const connectionResult = await stripeTerminal.connectReader(reader);
if (connectionResult.error) {
console.error("Connection failed:", connectionResult.error.message);
alert(`Connection failed: ${connectionResult.error.message}`);
return false;
}
console.log("Successfully connected to reader:", connectionResult.reader.label);
alert(`Connected to reader: ${connectionResult.reader.label}`);
return true;
} catch (error) {
console.error("Error while connecting to reader:", error);
alert("An unexpected error occurred during the reader connection. Check console for details.");
return false;
}
}
// Example flow to discover and connect to a reader
async function setupReader() {
const reader = await findReaders();
if (reader) {
await linkReader(reader);
}
}
I have managed to connect the reader using the Stripe API; I can check if the reader is online from my Stripe dashboard. However, upon attempting to process a payment to the reader, I receive an error stating No reader found. Check connectivity and network configuration..
Interestingly, when executing this code:
import stripe
stripe.api_key = "sk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
try:
# Retrieve all connected readers
available_readers = stripe.terminal.Reader.list()
print("Available Readers:", available_readers)
except stripe.error.StripeError as error:
print("Stripe error occurred:", error)
except Exception as error:
print("Unexpected error occurred:", error)
The output displays:
Available Readers: {
"data": [{
"device_sw_version": "2.27.7.0",
"device_type": "bbpos_wisepos_e",
"id": "tmr_XXXXXXXXXXXXXX",
"ip_address": "x.0.0.xxx",
"label": "Testing_Reader",
"last_seen_at": 1735518518163,
"livemode": true,
"location": "tml_ZZZZZZZZZZZZ",
"status": "online"
}],
"has_more": false
}
Further, executing this command: stripe terminal readers list
yields:
{
"object": "list",
"data": [{
"id": "tmr_XXXXXXXXXXXXXX",
"status": "online"
}]
}
This leads me to question why the button with the ID send-to-terminal
causes the earlier mentioned error when clicked.
More context: I’ve implemented the following service:
import stripe
import logging
from decimal import Decimal
from django.conf import settings
class PaymentHandler:
def __init__(self):
stripe.api_key = settings.STRIPE_SECRET_KEY
self.logger = logging.getLogger(__name__)
def fetch_online_reader(self):
try:
readers = stripe.terminal.Reader.list(status="online").data
if not readers:
self.logger.error("No online terminal reader found.")
raise ValueError("No online terminal reader found.")
return readers[0]
except stripe.error.StripeError as error:
self.logger.error(f"Stripe error while fetching readers: {str(error)}")
raise Exception(f"Stripe error: {str(error)}")
def initialize_payment_intent(self, amount, currency="CAD", methods=None, capture="automatic"):
try:
if methods is None:
methods = ["card_present"]
intent = stripe.PaymentIntent.create(
amount=int(round(amount, 2) * 100),
currency=currency.lower(),
payment_method_types=methods,
capture_method=capture
)
self.logger.info(f"PaymentIntent created: {intent['id']}")
return intent
except stripe.error.StripeError as error:
self.logger.error(f"Error creating PaymentIntent: {str(error)}")
raise Exception(f"Error: {str(error)}")
except Exception as error:
self.logger.error(f"Unexpected error: {str(error)}")
raise Exception(f"Unexpected error: {str(error)}")
def process_payment(self, intent_id):
try:
reader_id = settings.STRIPE_READER_ID
response = stripe.terminal.Reader.process_payment_intent(reader_id, {"payment_intent": intent_id})
self.logger.info(f"PaymentIntent {intent_id} processed for reader {reader_id}.")
return response
except stripe.error.StripeError as error:
self.logger.error(f"Stripe error during payment process: {str(error)}")
raise Exception(f"Stripe error: {str(error)}")
except Exception as error:
self.logger.error(f"Unexpected error during payment: {str(error)}")
raise Exception(f"Unexpected error: {str(error)}")
And I have these views implemented:
@login_required
def send_payment(request, order_id):
if request.method == "POST":
try:
amount = Decimal(request.POST.get('amount', 0))
if amount <= 0:
return JsonResponse({'success': False, 'error': 'Invalid amount.'}, status=400)
payment_intent = stripe.PaymentIntent.create(
amount=int(amount * 100),
currency="CAD",
payment_method_types=["card_present"]
)
online_readers = stripe.terminal.Reader.list(status="online").data
if not online_readers:
return JsonResponse({'success': False, 'error': 'No online reader found.'}, status=404)
reader = online_readers[0]
response = stripe.terminal.Reader.process_payment_intent(reader["id"], {"payment_intent": payment_intent["id"]})
if response.get("status") == "succeeded":
return JsonResponse({'success': True, 'payment_intent_id': payment_intent["id"], 'message': 'Payment successfully sent to terminal.'})
else:
return JsonResponse({'success': False, 'error': response.get("error", "Unknown terminal error.")}, status=400)
except stripe.error.StripeError as error:
return JsonResponse({'success': False, 'error': f"Stripe Error: {str(error)}"}, status=500)
except Exception as error:
return JsonResponse({'success': False, 'error': f"Unexpected error: {str(error)}"}, status=500)
return JsonResponse({'success': False, 'error': 'Method not allowed.'}, status=405)
@csrf_exempt
def generate_connection_token(request):
try:
token = stripe.terminal.ConnectionToken.create()
return JsonResponse({"secret": token.secret})
except stripe.error.StripeError as error:
return JsonResponse({"error": str(error)}, status=500)
except Exception as error:
return JsonResponse({"error": f"Unexpected error: {str(error)}"}, status=500)
I’m looking for assistance in understanding why the connection fails when attempting to send data to the terminal.