# Print content on a reader Print content on a reader's embedded printer. With Stripe Terminal, you can print custom content—such as receipts, tickets, or other documents—directly on a reader’s embedded printer. This feature is only available for the [Verifone V660p](https://stripe.com/terminal/v660p) reader, which is equipped with an embedded thermal printer capable of printing in black and white. ## Generating print content Your integration is responsible for generating the content to print as an image file. Images are the only format that we support for printing. After you have an image, convert it to the native image representation for your integration type (for example, an image file for server-driven or a [Bitmap](https://developer.android.com/reference/kotlin/android/graphics/Bitmap.html) for Android). ### Content guidelines For best results, we recommend images that are: - At most 384 pixels wide - Black and white (no color) - Designed so that the thinnest part of any character or line is at least 2 pixels wide, to make sure printing is clear and legible > You’re legally responsible for any content submitted to Stripe for printing using readers, and must make sure your receipts comply with applicable law. You’re prohibited from printing receipts containing materials that (i) infringe on the rights of any third party, (ii) violate applicable law, or (iii) contain objectionable, offensive, deceptive, inaccurate, or harmful content. ## Printing content #### Server-driven - [print_content](https://docs.stripe.com/api/terminal/readers/print_content.md) To print content on a reader, call the [print_content](https://docs.stripe.com/api/terminal/readers/print_content.md) endpoint. Send a `multipart/form-data` body with your PNG or JPEG image file. The uploaded file must not exceed 100 KB. ```curl curl https://files.stripe.com/v1/terminal/readers/tmr_FDOt2wlRZEdpd7/print_content \ -u "<>:" \ -F type=image \ -F "image=@/path/to/a/image.png" ``` > This endpoint lives on the `files.stripe.com` subdomain instead of `api.stripe.com`. #### Android - [print (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/print.html) To print content using the Android SDK, pass an instance of the native [Bitmap](https://developer.android.com/reference/kotlin/android/graphics/Bitmap.html) class as `PrintContent` to the [print](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/print.html) method. #### Kotlin ```kotlin val bitmap = createBitmap(384, /* some height */ ) // A width of 384 pixels is recommended // Generate print content here val printContent = PrintContent.Bitmap.create(bitmap) Terminal.getInstance().print( printContent, object : Callback { override fun onSuccess() { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` #### iOS - [print (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)print:completion:) To print content using the iOS SDK, pass an instance of the native [UIImage](https://developer.apple.com/documentation/uikit/uiimage) class to the [print](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)print:completion:) method. #### Swift ```swift let image = UIImage(named: "receipt") // Generate print content here let content = try PrintContentBuilder(image: image).build() Terminal.shared.print(content) { (error) in // Check for errors } ``` #### JavaScript - [print (JavaScript)](https://docs.stripe.com/terminal/references/api/js-sdk.md#print) To print content using the JavaScript SDK, pass a native [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement) object to the [print](https://docs.stripe.com/terminal/references/api/js-sdk.md#print) method. #### JavaScript ```javascript const canvas = document.createElement('canvas'); canvas.width = 384; canvas.height = /* some height */; // Generate print content here const result = await terminal.print(canvas); if ('error' in result) { // Placeholder for handling exception } else { // Placeholder for handling successful operation } ``` #### React Native - [print (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#print) To print content using the React Native SDK, pass an image encoded as a base64 string or `data:` URI scheme to the [print](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#print) method. #### TypeScript ```typescript const { print } = useStripeTerminal(); // JPEG/PNG image encoded as a base64 string const imageUri = "iVBORw0KGgoAAAANSUhEUgAAAAcAAAAFCAYAAACJmvbYAAAAN0lEQVR4AUyLCQ4AQATExv7/z1YniERd5UnKgriVPpGIS9QAGsll7Rz0YMkV2HRijvns3RY+8wMAAP//S2WPFgAAAAZJREFUAwBWNAoHH+0LdQAAAABJRU5ErkJggg=="; const { error } = await print(imageUri); if (error) { // Placeholder for handling exception } else { // Placeholder for handling successful operation } ``` ## Handle the print result #### Server-driven The [print_content](https://docs.stripe.com/api/terminal/readers/print_content.md) endpoint responds with an updated [Reader](https://docs.stripe.com/api/terminal/readers/object.md) object when the print command successfully sends to the reader. See the following example response: ```json { "id": "tmr_FDOt2wlRZEdpd7", "object": "terminal.reader", "action": { "failure_code": null, "failure_message": null, "print_content": { "image": { "created_at": 1748971913, "filename": "image.png", "size": 15864, "type": "png" }, "type": "image" }, "status": "in_progress", "type": "print_content" }, "device_sw_version": "2.37.2.0", "device_type": "verifone_v660p", "ip_address": "0.0.0.0", "label": "Blue Rabbit", "last_seen_at": 1695166525506, "livemode": false, "location": "tml_FDOtHwxAAdIJOh", "metadata": {}, "serial_number": "452-406-028", "status": "online" } ``` The `action` object shows that a `print_content` action is `in_progress`. The `print_content` object contains information about the image being printed. The endpoint immediately responds to a validation error (for example, file too large or unsupported format) with a `400` status code and a body, such as the following: ```json { "error": { "message": "The file you uploaded was too large. Please upload a file smaller than 100 KB", "param": "image", "request_log_url": "https://dashboard.stripe.com/...", "type": "invalid_request_error" } } ``` #### Webhook events When the print operation completes (either successfully or with an error), Stripe sends a request to your [webhook endpoint](https://docs.stripe.com/webhooks.md). Stripe sends two webhook events to notify your back end of the print command’s result: - `terminal.reader.action_succeeded`: The print command succeeded. - `terminal.reader.action_failed`: The print command failed. For example, the printer ran out of paper or jammed during printing. The webhook payload contains an [event object](https://docs.stripe.com/api/events/object.md) where `data.object` is an updated [Reader](https://docs.stripe.com/api/terminal/readers/object.md) object. ##### The `terminal.reader.action_succeeded` event For a `terminal.reader.action_succeeded` event, the `data` object looks like the following: ```json { "object": { "id": "tmr_FDOt2wlRZEdpd7", "object": "terminal.reader", "action": { "failure_code": null, "failure_message": null, "print_content": { "image": { "created_at": 1748971913, "filename": "image.png", "size": 15864, "type": "png" }, "type": "image" }, "status": "succeeded", "type": "print_content" }, "device_deploy_group": "", "device_sw_version": "2.34.0.0", "device_type": "verifone_v660p", "ip_address": "10.244.38.93", "label": "test", "livemode": false, "location": "tml_GEPlmAJnZUoXI6", "metadata": {}, "serial_number": "452-406-028", "software": null, "status": "online" }, "previous_attributes": null } ``` The `action.status` is set to `succeeded`. The `action.failure_code` and `action.failure_message` are both `null` in this case. ##### The `terminal.reader.action_failed` event For a `terminal.reader.action_failed` event, the `data` object looks like the following: ```json { "object": { "id": "tmr_FDOt2wlRZEdpd7", "object": "terminal.reader", "action": { "failure_code": "reason_out_of_paper", "failure_message": "The printer is out of paper.", "print_content": { "image": { "created_at": 1748971913, "filename": "image.png", "size": 15864, "type": "png" }, "type": "image" }, "status": "failed", "type": "print_content" }, "device_deploy_group": "", "device_sw_version": "2.34.0.0", "device_type": "verifone_v660p", "ip_address": "10.244.35.107", "label": "test", "livemode": false, "location": "tml_GEPlmAJnZUoXI6", "metadata": {}, "serial_number": "452-406-028", "software": null, "status": "online" }, "previous_attributes": null } ``` The `action.status` is set to `failed`. The `failure_code` field contains the reason for the failure, and the `failure_message` field contains a human readable message describing the failure. The possible values for the `failure_code` field are: | Error Description | Failure Code | | --------------------------------------------------------- | ---------------------- | | The printer is currently printing. | `printer_busy` | | The printer paper roll is jammed. | `printer_paperjam` | | The printer is out of paper. | `printer_out_of_paper` | | The printer’s cover or head assembly is open. | `printer_cover_open` | | General failure to print (catch all for any other error). | `printer_failure` | If the reader doesn’t support printing, the `failure_code` is set to `printer_not_supported` and the error returns immediately after the [print_content](https://docs.stripe.com/api/terminal/readers/print_content.md) endpoint is called. A `terminal.reader.action_failed` event isn’t sent. #### Android After the print command completes, the Android SDK calls either the `onSuccess` or `onFailure` function of the [`Callback`](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-callback/index.html) object. In the case of a print failure, the `onFailure` function is called with a [`TerminalException`](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-exception/index.html) object with one of the following `TerminalErrorCode` values: - `PRINTER_BUSY` - `PRINTER_PAPERJAM` - `PRINTER_OUT_OF_PAPER` - `PRINTER_COVER_OPEN` - `PRINTER_ABSENT` - `PRINTER_UNAVAILABLE` - `PRINTER_ERROR` Learn more about these error codes in the [`TerminalErrorCode` reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/index.html#-556602182%2FClasslikes%2F-1219334616). #### iOS After the print command completes, the iOS SDK calls the provided `completion` block. If successful, the block is called with `nil`. In the case of a print failure, the block is called with an `NSError` object with one of the following `SCPError` codes: | Objective-C | Swift | | -------------------- | -------------------- | | `PrinterBusy` | `printerBusy` | | `PrinterPaperJam` | `printerPaperJam` | | `PrinterOutOfPaper` | `printerOutOfPaper` | | `PrinterCoverOpen` | `printerCoverOpen` | | `PrinterAbsent` | `printerAbsent` | | `PrinterUnavailable` | `printerUnavailable` | | `PrinterError` | `printerError` | Learn more about these error codes in the [`SCPError` reference](https://stripe.dev/stripe-terminal-ios/docs/Enums/SCPError.html#/c:@E@SCPError@SCPErrorPrinterBusy). #### JavaScript The [print](https://docs.stripe.com/terminal/references/api/js-sdk.md#print) method returns a `Promise` that resolves to an empty object if the print command succeeds. If the command fails, the `Promise` resolves to an object with an `error` field. The `error` object contains an error `code`, as well as a human-readable `message`. The possible values for the `code` field are: - `printer_busy` - `printer_paperjam` - `printer_cover_open` - `printer_out_of_paper` - `printer_absent` - `printer_unavailable` - `printer_error` See the [Error codes reference](https://docs.stripe.com/terminal/references/api/js-sdk.md#error-codes). #### React Native The [print](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#print) method returns a `Promise` that resolves to an empty object if the print command succeeds. If the command fails, the `Promise` resolves to an object with an `error` field. The value of `error` is a [StripeError](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeError.html) object containing a specific [ErrorCode](https://stripe.dev/stripe-terminal-react-native/api-reference/types/ErrorCode.html), a human-readable `message`, and additional details such as `apiError` and `underlyingError`.