# BlockChyp Rust SDK [![Build Status](https://github.com/blockchyp/blockchyp-rust/actions/workflows/main.yml/badge.svg)](https://github.com/blockchyp/blockchyp-rust/actions/workflows/main.yml) [![Release](https://img.shields.io/github/release/blockchyp/blockchyp-rust/all.svg?style=shield)](https://github.com/blockchyp/blockchyp-rust/releases/latest) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/blockchyp/blockchyp-go/blob/master/LICENSE) This is the SDK for Rust. Like all BlockChyp SDKs, it provides a full client for the BlockChyp gateway and BlockChyp payment terminals. ## Installation The BlockChyp SDK is installable via Cargo. Type the following command to add BlockChyp to your Cargo.toml. ``` cargo add blockchyp ``` ## A Simple Example Running your first transaction is easy. Make sure you have a BlockChyp terminal, activate it, and generate a set of API keys. ``` use ::blockchyp::*; fn main() { let creds = APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; let client = Client::new(creds); let mut request = AuthorizationRequest{ test: true, terminal_name: "Test Terminal".to_string(), amount: "55.00".to_string(), ..Default::default() }; let (response, err) = client.charge(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return } if response.approved { println!("approved"); } println!("Response: {:?}", response); } ``` The response contains all the information you'll need to complete processing a transaction. Of particular importance is the ReceiptSuggestions struct, which contains all the fields that are required or recommended for PCI or EMV compliance. ## Additional Documentation Complete documentation can be found on our [Developer Documentation Portal]. [Developer Documentation Portal]: https://docs.blockchyp.com/ ## Getting a Developer Kit In order to test your integration with real terminals, you'll need a BlockChyp Developer Kit. Our kits include a fully functioning payment terminal with test pin encryption keys. Every kit includes a comprehensive set of test cards with test cards for every major card brand and entry method, including Contactless and Contact EMV and mag stripe cards. Each kit also includes test gift cards for our blockchain gift card system. Access to BlockChyp's developer program is currently invite only, but you can request an invitation by contacting our engineering team at **nerds@blockchyp.com**. You can also view a number of long form demos and learn more about us on our [YouTube Channel](https://www.youtube.com/channel/UCE-iIVlJic_XArs_U65ZcJg). ## Transaction Code Examples You don't want to read words. You want examples. Here's a quick rundown of the stuff you can do with the BlockChyp Rust SDK and a few basic examples. ### Payment Endpoints These are the core payment APIs used to execute and work with payment transactions in BlockChyp. #### Charge * **API Credential Types:** Merchant * **Required Role:** Payment API Access Our most popular transaction executes a standard authorization and capture. This is the most basic of basic payment transactions, typically used in conventional retail. Charge transactions can use a payment terminal to capture a payment or use a previously enrolled payment token. **Terminal Transactions** For terminal transactions, make sure you pass in the terminal name using the `terminalName` property. **Token Transactions** If you have a payment token, omit the `terminalName` property and pass in the token with the `token` property instead. **Card Numbers and Mag Stripes** You can also pass in PANs and Mag Stripes, but you probably shouldn't, as this will put you in PCI scope and the most common vector for POS breaches is keylogging. If you use terminals for manual card entry, you'll bypass any keyloggers that might be maliciously running on the point-of-sale system. **Common Variations** * **Gift Card Redemption**: There's no special API for gift card redemption in BlockChyp. Simply execute a plain charge transaction and if the customer swipes a gift card, our terminals will identify the gift card and run a gift card redemption. Also note that if for some reason the gift card's original purchase transaction is associated with fraud or a chargeback, the transaction will be rejected. * **EBT**: Set the `card_type` field to `blockchyp::CardType::EBT` to process an EBT SNAP transaction. Note that test EBT transactions always assume a balance of $100.00, so test EBT transactions over that amount may be declined. * **Cash Back**: To enable cash back for debit transactions, set the `cash_back` field. If the card presented isn't a debit card, the `cash_back` field will be ignored. * **Manual Card Entry**: Set the `manual_entry` field to enable manual card entry. Good as a backup when chips and MSR's don't work or for more secure phone orders. You can even combine the `manual_entry` field with the `card_type` field set to `blockchyp::CardType::EBT` for manual EBT card entry. * **Inline Tokenization**: You can enroll the payment method in the token vault inline with a charge transaction by setting the `enroll` field. You'll get a token back in the response. You can even bind the token to a customer record if you also pass in customer data. * **Prompting for Tips**: Set the `prompt_for_tip` field if you'd like to prompt the customer for a tip before authorization. Good for pay-at-the-table and other service related scenarios. * **Cash Discounting and Surcharging**: The `surcharge` and `cash_discount` fields can be used together to support cash discounting or surcharge problems. Consult the Cash Discount documentation for more details. * **Cryptocurrency** The `cryptocurrency` field can be used to switch the standard present card screen to a cryptocurrency screen. The field value can be `ANY` to enable any supported cryptocurrency or a single currency code such as `BTC` for Bitcoin. ```rust use blockchyp; use std::error::Error; fn charge_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::AuthorizationRequest{ test: true, terminal_name: "Test Terminal".to_string(), amount: "55.00".to_string(), ..Default::default() }; let (response, err) = client.charge(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { charge_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Preauthorization * **API Credential Types:** Merchant * **Required Role:** Payment API Access A preauthorization puts a hold on funds and must be captured later. This is used in scenarios where the final transaction amount might change. A common example is fine dining, where a tip adjustment is required before final settlement. Another use case for preauthorization is e-commerce. Typically, an online order is preauthorized at the time of the order and then captured when the order ships. Preauthorizations can use a payment terminal to capture a payment or use a previously enrolled payment token. **Terminal Transactions** For terminal transactions, make sure you pass in the terminal name using the `terminalName` property. **Token Transactions** If you have a payment token, omit the `terminalName` property and pass in the token with the `token` property instead. **Card Numbers and Mag Stripes** You can also pass in PANs and Mag Stripes, but you probably shouldn't, as this will put you in PCI scope and the most common vector for POS breaches is key logging. If you use terminals for manual card entry, you'll bypass any key loggers that might be maliciously running on the point-of-sale system. **Cryptocurrency** Note that preauths are not supported for cryptocurrency. **Common Variations** * **Manual Card Entry**: Set the `manual_entry` field to enable manual card entry. Good as a backup when chips and MSR's don't work or for more secure phone orders. You can even combine the `manual_entry` field with `card_type` set to `blockchyp::CardType::EBT` for manual EBT card entry. * **Inline Tokenization**: You can enroll the payment method in the token vault in line with a charge transaction by setting the `enroll` field. You'll get a token back in the response. You can even bind the token to a customer record if you also pass in customer data. * **Prompting for Tips**: Set the `prompt_for_tip` field if you'd like to prompt the customer for a tip before authorization. You can prompt for tips as part of a preauthorization, although it's not a very common approach. * **Cash Discounting and Surcharging**: The `surcharge` and `cash_discount` fields can be used together to support cash discounting or surcharge problems. Consult the Cash Discount documentation for more details. ```rust use blockchyp; use std::error::Error; fn preauth_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::AuthorizationRequest{ test: true, terminal_name: "Test Terminal".to_string(), amount: "27.00".to_string(), ..Default::default() }; let (response, err) = client.preauth(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { preauth_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Capture Preauthorization * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API allows you to capture a previously approved preauthorization. You'll need to make sure you pass in the Transaction ID returned by the original preauth transaction so we know which transaction we're capturing. If you want to capture the transaction for the exact amount of the preauth, the Transaction ID is all you need to pass in. You can adjust the total if you need to by passing in a new `amount`. We also recommend you pass in updated amounts for `tax` and `tip` as it can sometimes reduce your interchange fees. (Level II Processing, for example.) ```rust use blockchyp; use std::error::Error; fn capture_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::CaptureRequest{ test: true, transaction_id: "".to_string(), amount: "32.00".to_string(), ..Default::default() }; let (response, err) = client.capture(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { capture_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Refund * **API Credential Types:** Merchant * **Required Role:** Payment API Access It's not ideal, but sometimes customers want their money back. Our refund API allows you to confront this unpleasant reality by executing refunds in a few different scenarios. The most fraud resistent method is to execute refunds in the context of a previous transaction. You should always keep track of the Transaction ID returned in a BlockChyp response. To refund the full amount of the previous transaction, just pass in the original Transaction ID with the refund requests. **Partial Refunds** For a partial refund, just pass in an amount along with the Transaction ID. The only rule is that the amount must be equal to or less than the original transaction. You can execute multiple partial refunds against the same original transaction as long as the total refunded amount doesn't exceed the original amount. **Tokenized Refunds** You can also use a token to execute a refund. Pass in a token instead of the Transaction ID and the desired refund amount. **Free Range Refunds** When you execute a refund without referencing a previous transaction, we call this a *free range refund*. We don't recommend this type of refund, but it is permitted. If you absolutely insist on doing it, pass in a Terminal Name and an amount. You can execute a manual or keyed refund by passing the `manual_entry` field to a free range refund request. **Gift Card Refunds** Gift card refunds are allowed in the context of a previous transaction, but free range gift card refunds are not allowed. Use the gift card activation API if you need to add more funds to a gift card. **Store and Forward Support** Refunds are not permitted when a terminal falls back to store and forward mode. **Auto Voids** If a refund referencing a previous transaction is executed for the full amount before the original transaction's batch is closed, the refund is automatically converted to a void. This saves the merchant a little bit of money. **Cryptocurrency** Note that refunds are not supported for cryptocurrency. You must refund crypto transactions manually from your cryptocurrency wallet. ```rust use blockchyp; use std::error::Error; fn refund_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::RefundRequest{ transaction_id: "".to_string(), amount: "5.00".to_string(), ..Default::default() }; let (response, err) = client.refund(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { refund_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Void * **API Credential Types:** Merchant * **Required Role:** Payment API Access Mistakes happen. If a transaction is made by mistake, you can void it with this API. All that's needed is to pass in a Transaction ID and execute the void before the original transaction's batch closes. Voids work with EBT and gift card transactions with no additional parameters. **Cryptocurrency** Note that voids are not supported for cryptocurrency. You must refund crypto transactions manually from your cryptocurrency wallet. ```rust use blockchyp; use std::error::Error; fn void_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::VoidRequest{ test: true, transaction_id: "".to_string(), ..Default::default() }; let (response, err) = client.void(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { void_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Card Metadata * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API allows you to retrieve card metadata. Card metadata requests can use a payment terminal to retrieve metadata or use a previously enrolled payment token. **Terminal Transactions** For terminal transactions, make sure you pass in the terminal name using the `terminalName` property. **Token Transactions** If you have a payment token, omit the `terminalName` property and pass in the token with the `token` property instead. **Card Numbers and Mag Stripes** You can also pass in PANs and Mag Stripes, but you probably shouldn't, as this will put you in PCI scope and the most common vector for POS breaches is keylogging. If you use terminals for manual card entry, you'll bypass any keyloggers that might be maliciously running on the point-of-sale system. ```rust use blockchyp; use std::error::Error; fn card_metadata_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::CardMetadataRequest{ test: true, terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.card_metadata(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { card_metadata_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Time Out Reversal * **API Credential Types:** Merchant * **Required Role:** Payment API Access Payment transactions require a stable network to function correctly and no network is stable all the time. Time out reversals are a great line of defense against accidentally double charging consumers when payments are retried during shaky network conditions. We highly recommend developers use this API whenever a charge, preauth, or refund transaction times out. If you don't receive a definitive response from BlockChyp, you can't be certain about whether or not the transaction went through. The best practice in this situation is to send a time out reversal request. Time out reversals check for a transaction and void it if it exists. The only caveat is that developers must use the `transactionRef` property (`txRef` for the CLI) when executing charge, preauth, and refund transactions. The reason for this requirement is that if a system never receives a definitive response for a transaction, the system would never have received the BlockChyp generated Transaction ID. We have to fall back to Transaction Ref to identify a transaction. **Cryptocurrency** Note that refunds are not supported for cryptocurrency. You must refund crypto transactions manually from your cryptocurrency wallet. ```rust use blockchyp; use std::error::Error; fn reverse_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::AuthorizationRequest{ transaction_ref: "".to_string(), ..Default::default() }; let (response, err) = client.reverse(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { reverse_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Gift Card Activation * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API activates or adds value to BlockChyp gift cards. Just pass in the terminal name and the amount to add to the card. Once the customer swipes their card, the terminal will use keys on the mag stripe to add value to the card. You don't need to handle a new gift card activation or a gift card recharge any differently. The terminal firmware will figure out what to do on its own while also returning the new balance for the gift card. This is the part of the system where BlockChyp's blockchain DNA comes closest to the surface. The BlockChyp gift card system doesn't really use gift card numbers. This means they can't be stolen. BlockChyp identifies cards with an elliptic curve public key instead. Gift card transactions are actually blocks signed with those keys. This means there are no shared secrets sent over the network. To keep track of a BlockChyp gift card, hang on to the **public key** returned during gift card activation. That's the gift card's elliptic curve public key. We sometimes print numbers on our gift cards, but these are actually decimal encoded hashes of a portion of the public key to make our gift cards seem *normal* to *normies*. They can be used for balance checks and play a lookup role in online gift card authorization, but are of little use beyond that. **Voids and Reversals** Gift card activations can be voided and reversed just like any other BlockChyp transaction. Use the Transaction ID or Transaction Ref to identify the gift activation transaction as you normally would for voiding or reversing a conventional payment transaction. **Importing Gift Cards** BlockChyp does have the ability to import gift card liability from conventional gift card platforms. Unfortunately, BlockChyp does not support activating cards on third party systems. However, you can import your outstanding gift cards and customers can swipe them on the terminals like BlockChyp's standard gift cards. No special coding is required to access this feature. The gateway and terminal firmware handle everything for you. **Third Party Gift Card Networks** BlockChyp does not currently provide any native support for other gift card platforms beyond importing gift card liability. We do have a white listing system that can be used to support your own custom gift card implementations. We have a security review process before we can allow a BIN range to be white listed, so contact support@blockchyp.com if you need to white list a BIN range. ```rust use blockchyp; use std::error::Error; fn gift_activate_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::GiftActivateRequest{ test: true, terminal_name: "Test Terminal".to_string(), amount: "50.00".to_string(), ..Default::default() }; let (response, err) = client.gift_activate(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.approved { println!("approved"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { gift_activate_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Balance * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API checks a gift or EBT card balance. **Gift Card Balance Checks** For gift cards, pass in a terminal name and the customer will be prompted to swipe a card on that terminal. The remaining balance will be displayed briefly on the terminal screen and the API response will include the gift card's public key and the remaining balance. **EBT Balance Checks** All EBT transactions require a PIN, so to check an EBT card balance, you need to pass in the `ebt` flag just like you would for a normal EBT charge transaction. The customer will be prompted to swipe their card and enter a PIN code. If everything checks out, the remaining balance on the card will be displayed on the terminal for the customer and returned with the API response. **Testing Gift Card Balance Checks** Test gift card balance checks work no differently than live gift cards. You must activate a test gift card first to test balance checks. Test gift cards are real blockchain cards that live on our parallel test blockchain. **Testing EBT Gift Card Balance Checks** All test EBT transactions assume a starting balance of $100.00. As a result, test EBT balance checks always return a balance of $100.00. ```rust use blockchyp; use std::error::Error; fn balance_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::BalanceRequest{ test: true, terminal_name: "Test Terminal".to_string(), card_type: blockchyp::CardType::EBT, ..Default::default() }; let (response, err) = client.balance(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { balance_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Close Batch * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API will close the merchant's batch if it's currently open. By default, merchant batches will close automatically at 3 AM in their local time zone. The automatic batch closure time can be changed in the Merchant Profile or disabled completely. If automatic batch closure is disabled, you'll need to use this API to close the batch manually. ```rust use blockchyp; use std::error::Error; fn close_batch_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::CloseBatchRequest{ test: true, ..Default::default() }; let (response, err) = client.close_batch(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { close_batch_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Send Payment Link * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API allows you to send an invoice to a customer and capture payment via a BlockChyp hosted payment page. If you set the `autoSend` flag, BlockChyp will send a basic invoice email to the customer for you that includes the payment link. If you'd rather have more control over the look of the email message, you can omit the `autoSend` flag and send the customer email yourself. There are a lot of optional parameters for this API, but at a minimum you'll need to pass in a total, customer name, and email address. (Unless you use the `cashier` flag.) **Customer Info** Unless you're using the `cashier` flag, you must specify a customer; either by creating a new customer record inline or passing in an existing Customer ID or Customer Ref. **Line Item Level Data** It's not strictly required, but we strongly recommend sending line item level detail with every request. It will make the invoice look more complete and the data format for line item level data is the exact same format used for terminal line item display, so the same code can be used to support both areas. **Descriptions** You can also provide a free form description or message to display near the bottom of the invoice. Usually this is some kind of thank you note or instruction. **Terms and Conditions** You can include long form contract language with a request and capture terms and conditions accepted at the same time payment is captured. The interface is identical to that used for the terminal based Terms and Conditions API in that you can pass in content directly via `tcContent` or via a preconfigured template via `tcAlias`. The Terms and Conditions log will also be updated when agreement acceptance is incorporated into a send link request. **Auto Send** BlockChyp does not send the email notification automatically. This safeguard prevents real emails from going out when you may not expect them If you want BlockChyp to send the email for you, just add the `autoSend` flag with all requests. **Cryptocurrency** If the merchant is configured to support cryptocurrency transactions, the payment page will display additional UI widgets that allowing customers to switch to a crypto payment method. **Tokenization** Add the `enroll` flag to a send link request to enroll the payment method in the token vault. Add the `enrollOnly` flag to enroll the payment method in the token vault without any immediate payment taking place. The payment link will ask the user for their payment information and inform them that they will not be charged immediately, but that their payment may be used for future transactions. **Cashier Facing Card Entry** BlockChyp can be used to generate internal/cashier facing card entry pages as well. This is designed for situations where you might need to take a phone order and don't have an available terminal. If you pass in the `cashier` flag, no email will be sent and you'll be able to load the link in a browser or iframe for payment entry. When the `cashier` flag is used, the `autoSend` flag will be ignored. Note that cryptocurrency is not supported for cashier facing payment entry. **Payment Notifications** When a customer successfully submits payment, the merchant will receive an email notifying them that the payment was received. **Real Time Callback Notifications** Email notifications are fine, but you may want your system to be informed immediately whenever a payment event occurs. By using the optional `callbackUrl` request property, you can specify a URL to which the Authorization Response will be posted every time the user submits a payment, whether approved or otherwise. The response will be sent as a JSON encoded POST request and will be the exact same format as all BlockChyp charge and preauth transaction responses. **Status Polling** If real time callbacks aren't practical or necessary in your environment, you can always use the Payment Link Status API described futher on. A common use case for the send link API with status polling is curbside pickup. You could have your system check the Payment Link Status when a customer arrives to ensure it's been paid without necessarily needing to create background threads to constantly poll for status updates. ```rust use blockchyp; use std::error::Error; fn send_payment_link_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::PaymentLinkRequest{ transaction_ref: "".to_string(), amount: "199.99".to_string(), description: "Widget".to_string(), subject: "Widget invoice".to_string(), transaction: Some(blockchyp::TransactionDisplayTransaction{ subtotal: "195.00".to_string(), tax: "4.99".to_string(), total: "199.99".to_string(), items: Some(vec![ blockchyp::TransactionDisplayItem{ description: "Widget".to_string(), price: "195.00".to_string(), quantity: 1.0, ..Default::default() }, ]), ..Default::default() }), auto_send: true, customer: blockchyp::Customer{ customer_ref: "Customer reference string".to_string(), first_name: "FirstName".to_string(), last_name: "LastName".to_string(), company_name: "Company Name".to_string(), email_address: "notifications@blockchypteam.m8r.co".to_string(), sms_number: "(123) 123-1231".to_string(), ..Default::default() }, ..Default::default() }; let (response, err) = client.send_payment_link(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { send_payment_link_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Resend Payment Link * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API will resend a previously created payment link. An error is returned if the payment link is expired, has been cancelled, or has already been paid. ```rust use blockchyp; use std::error::Error; fn resend_payment_link_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::ResendPaymentLinkRequest{ link_code: "".to_string(), ..Default::default() }; let (response, err) = client.resend_payment_link(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { resend_payment_link_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Cancel Payment Link * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API cancels a payment link. ```rust use blockchyp; use std::error::Error; fn cancel_payment_link_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::CancelPaymentLinkRequest{ link_code: "".to_string(), ..Default::default() }; let (response, err) = client.cancel_payment_link(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { cancel_payment_link_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Payment Link Status * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API allows you to check on the status of a payment link, including transaction data and the full history of attempted transactions. This API is the preferred source of truth and best practice when you want to check on the status of a payment link (as opposed to Transaction Status). The Transaction Status API is not ideal because of ambiguity when there are multiple transactions associated with a single payment link. You must pass the `linkCode` value associated with the payment link. It is included in the response from BlockChyp when the payment link is originally created. ```rust use blockchyp; use std::error::Error; fn payment_link_status_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::PaymentLinkStatusRequest{ link_code: "".to_string(), ..Default::default() }; let (response, err) = client.payment_link_status(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { payment_link_status_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Transaction Status * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API returns the current status for any transaction. You can lookup a transaction by its BlockChyp assigned Transaction ID or your own Transaction Ref. You should always use globally unique Transaction Ref values, but in the event that you duplicate Transaction Refs, the most recent transaction matching your Transaction Ref is returned. ```rust use blockchyp; use std::error::Error; fn transaction_status_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TransactionStatusRequest{ transaction_id: "".to_string(), ..Default::default() }; let (response, err) = client.transaction_status(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { transaction_status_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Cash Discount * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API calculates the surcharge, cash discount, and total amounts for cash transactions. If you're using BlockChyp's cash discounting features, you can use this endpoint to ensure the numbers and receipts for true cash transactions are consistent with transactions processed by BlockChyp. ```rust use blockchyp; use std::error::Error; fn cash_discount_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::CashDiscountRequest{ amount: "100.00".to_string(), cash_discount: true, surcharge: true, ..Default::default() }; let (response, err) = client.cash_discount(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { cash_discount_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Batch History * **API Credential Types:** Merchant * **Required Role:** Payment API Access This endpoint allows developers to query the gateway for the merchant's batch history. The data will be returned in descending order of open date with the most recent batch returned first. The results will include basic information about the batch. Consider using the Batch Details API for more detail about a specific batch. **Limiting Results** This API will return a maximum of 250 results. Use the `maxResults` property to limit maximum results even further and use the `startIndex` property to page through results that span multiple queries. For example, if you want the ten most recent batches, pass in a value of `10` for `maxResults`. Also note that `startIndex` is zero based. Use a value of `0` to get the first batch in the dataset. **Filtering by Date Range** You can also filter results by date. Use the `startDate` and `endDate` properties to return only those batches opened between those dates. You can use either `startDate` and `endDate` and you can use date filters in conjunction with `maxResults` and `startIndex` ```rust use blockchyp; use std::error::Error; fn batch_history_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::BatchHistoryRequest{ max_results: 250, start_index: 0, ..Default::default() }; let (response, err) = client.batch_history(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { batch_history_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Batch Details * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API allows developers to pull down details for a specific batch, including captured volume, gift card activity, expected deposit, and captured volume broken down by terminal. The only required request parameter is `batchId`. Batch IDs are returned with every transaction response and can be discovered using the Batch History API. ```rust use blockchyp; use std::error::Error; fn batch_details_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::BatchDetailsRequest{ batch_id: "".to_string(), ..Default::default() }; let (response, err) = client.batch_details(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { batch_details_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Transaction History * **API Credential Types:** Merchant * **Required Role:** Payment API Access This endpoint provides several different methods to sift through transaction history. By default with no filtering properties, this endpoint will return the 250 most recent transactions. **Limiting Results** This API will return a maximum of 50 results in a single query. Use the `maxResults` property to limit maximum results even further and use the `startIndex` property to page through results that span multiple queries. For example, if you want the ten most recent batches, pass in a value of `10` for `maxResults`. Also note that `startIndex` is zero based. Use a value of `0` to get the first transaction in the dataset. **Filtering By Date Range** You can also filter results by date. Use the `startDate` and `endDate` properties to return only transactions run between those dates. You can use either `startDate` or `endDate` and you can use date filters in conjunction with `maxResults` and `startIndex` **Filtering By Batch** To restrict results to a single batch, pass in the `batchId` parameter. **Filtering By Terminal** To restrict results to those executed on a single terminal, pass in the terminal name. **Combining Filters** None of the above filters are mutually exclusive. You can combine any of the above properties in a single request to restrict transaction results to a narrower set of results. **Searching Transaction History** You can search transaction history by passing in search criteria with the `query` option. The search system will match the amount (requested and authorized), last four of the card number, cardholder name, and the auth code. Note that when search queries are used, terminalName or batch id filters are not supported. ```rust use blockchyp; use std::error::Error; fn transaction_history_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TransactionHistoryRequest{ max_results: 10, batch_id: "".to_string(), ..Default::default() }; let (response, err) = client.transaction_history(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { transaction_history_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### List Queued Transactions * **API Credential Types:** Merchant * **Required Role:** Payment API Access Returns a list of transaction refs of transactions queued on a terminal. Details about the transactions can be retrieved using the Transaction Status API. ```rust use blockchyp; use std::error::Error; fn list_queued_transactions_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::ListQueuedTransactionsRequest{ terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.list_queued_transactions(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { list_queued_transactions_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Delete Queued Transaction * **API Credential Types:** Merchant * **Required Role:** Payment API Access Deletes one or all queued transactions from a terminal. If `*` is passed as a transaction ref, then the entire terminal queue will be cleared. An error is returned if the passed transaction ref is not queued on the terminal. ```rust use blockchyp; use std::error::Error; fn delete_queued_transaction_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::DeleteQueuedTransactionRequest{ terminal_name: "Test Terminal".to_string(), transaction_ref: "*".to_string(), ..Default::default() }; let (response, err) = client.delete_queued_transaction(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { delete_queued_transaction_example()?; println!("Example completed successfully!"); Ok(()) } ``` ### Terminal Management Endpoints These APIs support terminal management functions and additional terminal features such as line item display, messages, and interactive prompts. These features can be used to extend a point of sale system's functionality. #### Terminal Ping * **API Credential Types:** Merchant * **Required Role:** Payment API Access This simple test transaction helps ensure good communication with a payment terminal and is usually the first test you'll run in development. It tests communication with the terminal and returns a positive response if everything is okay. It works the same way in local or cloud relay mode. If you get a positive response, you've successfully verified all of the following: * The terminal is online. * There is a valid route to the terminal. * The API Credentials are valid. ```rust use blockchyp; use std::error::Error; fn ping_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::PingRequest{ terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.ping(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { ping_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Terminal Locate * **API Credential Types:** Merchant * **Required Role:** Payment API Access This endpoint returns a terminal's routing and location information. The result will indicate whether or not the terminal is in cloud relay mode and will return the local IP address if the terminal is in local mode. The terminal will also return the public key for the terminal. ```rust use blockchyp; use std::error::Error; fn locate_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::LocateRequest{ terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.locate(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { locate_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Terminal Clear * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API interrupts whatever a terminal may be doing and returns it to the idle state. ```rust use blockchyp; use std::error::Error; fn clear_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::ClearTerminalRequest{ test: true, terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.clear(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { clear_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Terminal Status * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API returns the current status of a payment terminal. This is typically used as a way to determine if the terminal is busy before sending a new transaction. If the terminal is busy, `idle` will be false and the `status` field will return a short string that indicates the transaction type currently in progress. The system will also return the timestamp of the last status change in the `since` field. The `cardInSlot` field in the response will indicates whether or not a card is currently in the card reader slot. If the system is running a payment transaction and you wisely passed in a Transaction Ref, this API will also return the Transaction Ref of the in progress transaction. The table below lists all possible status responses. | Status Code | Description | |----------------------|-----------------------------------------------------------------------------------------| | idle | The terminal is idle and ready for transactions. The default branding is being displayed. | | activate | The terminal is in the process of activating and pairing with the merchant account. | | balance | A balance check (EBT or Gift Card) is pending on the terminal. | | boolean-prompt | A boolean prompt (yes/no) operation is pending on the terminal. | | signature | A signature capture is pending. | | crypto | A cryptocurrency transaction is pending. | | enroll | A token vault enrollment operation is pending. | | gift-activate | A gift card activation operation is in progress. | | message | The terminal is displaying a custom message. | | charge | The terminal is executing a charge transaction. | | preauth | The terminal is executing a preauth transaction. | | refund | The terminal is executing a refund transaction. | | survey | The terminal is displaying post transaction survey questions. | | terms-and-conditions | The terminal is pending terms and conditions acceptance and signature. | | text-prompt | The terminal is awaiting response to a text input prompt. | | txdisplay | The terminal is displaying transaction and/or line item level details. | ```rust use blockchyp; use std::error::Error; fn terminal_status_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::TerminalStatusRequest{ terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.terminal_status(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { terminal_status_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Capture Signature * **API Credential Types:** Merchant * **Required Role:** Payment API Access This endpoint captures a written signature from the terminal and returns the image. Unlike the Terms & Conditions API, this endpoint performs basic signature capture with no agreement display or signature archival. Under the hood, signatures are captured in a proprietary vector format and must be converted to a common raster format in order to be useful to most applications. At a minimum, you must specify an image format using the `sigFormat` parameter. Currently, JPG and PNG are supported. By default, images are returned in the JSON response as hex encoded binary. You can redirect the binary image output to a file using the `sigFile` parameter. You can also scale the output image to your preferred width by passing in a `sigWidth` parameter. The image will be scaled to that width, preserving the aspect ratio of the original image. ```rust use blockchyp; use std::error::Error; fn capture_signature_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::CaptureSignatureRequest{ terminal_name: "Test Terminal".to_string(), sig_format: blockchyp::SignatureFormat::PNG, sig_width: 200, ..Default::default() }; let (response, err) = client.capture_signature(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { capture_signature_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### New Transaction Display * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API sends totals and line item level data to the terminal. At a minimum, you should send total information as part of a display request, including `total`, `tax`, and `subtotal`. You can also send line item level data and each line item can have a `description`, `qty`, `price`, and `extended` price. If you fail to send an extended price, BlockChyp will multiply the `qty` by the `price`. However, we strongly recommend you precalculate all the fields yourself to ensure consistency. For example, your treatment of floating-point multiplication and rounding may differ slightly from BlockChyp's. **Discounts** You have the option to show discounts on the display as individual line items with negative values or you can associate discounts with a specific line item. You can apply any number of discounts to an individual line item with a description and amount. ```rust use blockchyp; use std::error::Error; fn new_transaction_display_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::TransactionDisplayRequest{ test: true, terminal_name: "Test Terminal".to_string(), transaction: Some(blockchyp::TransactionDisplayTransaction{ subtotal: "60.00".to_string(), tax: "5.00".to_string(), total: "65.00".to_string(), items: Some(vec![ blockchyp::TransactionDisplayItem{ description: "Leki Trekking Poles".to_string(), price: "35.00".to_string(), quantity: 2.0, extended: "70.00".to_string(), discounts: Some(vec![ blockchyp::TransactionDisplayDiscount{ description: "memberDiscount".to_string(), amount: "10.00".to_string(), ..Default::default() }, ]), ..Default::default() }, ]), ..Default::default() }), ..Default::default() }; let (response, err) = client.new_transaction_display(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { new_transaction_display_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Update Transaction Display * **API Credential Types:** Merchant * **Required Role:** Payment API Access Similar to *New Transaction Display*, this variant allows developers to update line item level data currently being displayed on the terminal. This feature is designed for situations where you want to update the terminal display as items are scanned. You'll only have to send information to the terminal that's changed, which usually means the new line item and updated totals. If the terminal is not in line item display mode and you invoke this endpoint, the first invocation will behave like a *New Transaction Display* call. At a minimum, you should send total information as part of a display request, including `total`, `tax`, and `subtotal`. You can also send line item level data and each line item can have a `description`, `qty`, `price`, and `extended` price. If you fail to send an extended price, BlockChyp will multiply the `qty` by the `price`. However, we strongly recommend you precalculate all the fields yourself to ensure consistency. For example, your treatment of floating-point multiplication and rounding may differ slightly from BlockChyp's. **Discounts** You have the option to show discounts on the display as individual line items with negative values or you can associate discounts with a specific line item. You can apply any number of discounts to an individual line item with a description and amount. ```rust use blockchyp; use std::error::Error; fn update_transaction_display_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::TransactionDisplayRequest{ test: true, terminal_name: "Test Terminal".to_string(), transaction: Some(blockchyp::TransactionDisplayTransaction{ subtotal: "60.00".to_string(), tax: "5.00".to_string(), total: "65.00".to_string(), items: Some(vec![ blockchyp::TransactionDisplayItem{ description: "Leki Trekking Poles".to_string(), price: "35.00".to_string(), quantity: 2.0, extended: "70.00".to_string(), discounts: Some(vec![ blockchyp::TransactionDisplayDiscount{ description: "memberDiscount".to_string(), amount: "10.00".to_string(), ..Default::default() }, ]), ..Default::default() }, ]), ..Default::default() }), ..Default::default() }; let (response, err) = client.update_transaction_display(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { update_transaction_display_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Display Message * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API displays a message on the payment terminal. Just specify the target terminal and the message using the `message` parameter. ```rust use blockchyp; use std::error::Error; fn message_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::MessageRequest{ test: true, terminal_name: "Test Terminal".to_string(), message: "Thank you for your business.".to_string(), ..Default::default() }; let (response, err) = client.message(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { message_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Boolean Prompt * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API prompts the customer to answer a yes or no question. You can specify the question or prompt with the `prompt` parameter and the response is returned in the `response` field. This can be used for a number of use cases including starting a loyalty enrollment workflow or customer facing suggestive selling prompts. **Custom Captions** You can optionally override the "YES" and "NO" button captions by using the `yesCaption` and `noCaption` request parameters. ```rust use blockchyp; use std::error::Error; fn boolean_prompt_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::BooleanPromptRequest{ test: true, terminal_name: "Test Terminal".to_string(), prompt: "Would you like to become a member?".to_string(), yes_caption: "Yes".to_string(), no_caption: "No".to_string(), ..Default::default() }; let (response, err) = client.boolean_prompt(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { boolean_prompt_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Text Prompt * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API prompts the customer to enter numeric or alphanumeric data. Due to PCI rules, free-form prompts are not permitted when the response could be any valid string. The reason for this is that a malicious developer (not you, of course) could use text prompts to ask the customer to input a card number or PIN code. This means that instead of providing a prompt, you provide a `promptType` instead. The prompt types currently supported are listed below: * **phone**: Captures a phone number. * **email**: Captures an email address. * **first-name**: Captures a first name. * **last-name**: Captures a last name. * **customer-number**: Captures a customer number. * **rewards-number**: Captures a rewards number. You can specify the prompt with the `promptType` parameter and the response is returned in the `response` field. ```rust use blockchyp; use std::error::Error; fn text_prompt_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::TextPromptRequest{ test: true, terminal_name: "Test Terminal".to_string(), prompt_type: blockchyp::PromptType::Email, ..Default::default() }; let (response, err) = client.text_prompt(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { text_prompt_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### List Terminals * **API Credential Types:** Merchant & Partner * **Required Role:** Terminal Management This API returns details about terminals associated with a merchant account. Status and resource information is returned for all terminals along with a preview of the current branding image displayed on the terminal ```rust use blockchyp; use std::error::Error; fn terminals_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TerminalProfileRequest{ ..Default::default() }; let (response, err) = client.terminals(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { terminals_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Deactivate Terminal * **API Credential Types:** Merchant & Partner * **Required Role:** Terminal Management This API deactivates a payment terminal. If the terminal exists and is currently online, it will be removed from the merchant's terminal inventory. The terminal will be remotely cleared and factory reset. ```rust use blockchyp; use std::error::Error; fn deactivate_terminal_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TerminalDeactivationRequest{ terminal_id: "".to_string(), ..Default::default() }; let (response, err) = client.deactivate_terminal(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { deactivate_terminal_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Activate Terminal * **API Credential Types:** Merchant & Partner * **Required Role:** Terminal Management This API activates a payment terminal. If successful, the payment terminal will restart, generate new encryption keys, and download any active branding assets for the merchant account it's been added to. Activation requests require an activation code and a unique terminal name. All terminal names must be unique across a merchant account. Optional Parameters * **merchantId:** For partner scoped API credentials, a merchant ID is required. For merchant scoped API credentials, the merchant ID is implicit and cannot be overridden. * **cloudRelay:** Activates the terminal in cloud relay mode. ```rust use blockchyp; use std::error::Error; fn activate_terminal_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TerminalActivationRequest{ terminal_name: "Test Terminal".to_string(), activation_code: "".to_string(), ..Default::default() }; let (response, err) = client.activate_terminal(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { activate_terminal_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Reboot Terminal * **API Credential Types:** Merchant * **Required Role:** Payment API Access This API reboots the terminal. ```rust use blockchyp; use std::error::Error; fn reboot_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::PingRequest{ terminal_name: "Test Terminal".to_string(), ..Default::default() }; let (response, err) = client.reboot(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { reboot_example()?; println!("Example completed successfully!"); Ok(()) } ``` ### Terms & Conditions Endpoints Developers can use BlockChyp to display and capture acceptance of contracts or agreements related to transactions. These agreements can be any long-form contract ranging from rental agreements to HIPPA disclosures. There are two basic approaches to terms and conditions capture. Merchants can store contract templates in BlockChyp or they can send the full agreement text as part of every API call. The right approach will largely depend on whether or not the system being integrated with BlockChyp already has a mechanism for organizing and managing agreements. For systems that already have this feature built in, it's probably not necessary to use Terms and Conditions. When agreements are displayed on a terminal, the consumer can scroll through and read the entire agreement, and provide a signature. Results are returned as part of the API response, but BlockChyp also stores a record of the agreement including the signature image, timestamp, and the full text of the agreement that was agreed to. The Terms and Conditions Log APIs can be used to search and retrieve acceptance records. Those records can also be linked to a transaction if a transaction id is provided with the original API request. #### Terms & Conditions Capture * **API Credential Types:** Merchant * **Required Role:** Terms & Conditions Management This API allows you to prompt a customer to accept a legal agreement on the terminal and (usually) capture their signature. Content for the agreement can be specified in two ways. You can reference a previously configured T&C template or pass in the full agreement text with every request. **Using Templates** If your application doesn't keep track of agreements you can leverage BlockChyp's template system. You can create any number of T&C Templates in the merchant dashboard and pass in the `tcAlias` flag to specify which one should display. **Raw Content** If your system keeps track of the agreement language or executes complicated merging and rendering logic, you can bypass our template system and pass in the full text with every transaction. Use `tcName` to pass in the agreement name and `tcContent` to pass in the contract text. Note that only plain text is supported. **Bypassing Signatures** Signature images are captured by default. If for some reason this doesn't fit your use case and you'd like to capture acceptance without actually capturing a signature image, set the `disableSignature` flag in the request. **Terms & Conditions Log** Every time a user accepts an agreement on the terminal, the signature image (if captured), will be uploaded to the gateway. The image will also be added to the log along with the full text of the agreement. This preserves the historical record in the event that standard agreements or templates change over time. **Associating Agreements with Transactions** To associate a Terms & Conditions log entry with a transaction, just pass in the Transaction ID or Transaction Ref for the associated transaction. ```rust use blockchyp; use std::error::Error; fn terms_and_conditions_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let mut request = blockchyp::TermsAndConditionsRequest{ test: true, terminal_name: "Test Terminal".to_string(), tc_alias: "hippa".to_string(), tc_name: "HIPPA Disclosure".to_string(), tc_content: "Full contract text".to_string(), sig_format: blockchyp::SignatureFormat::PNG, sig_width: 200, sig_required: true, ..Default::default() }; let (response, err) = client.terms_and_conditions(&mut request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { terms_and_conditions_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### List Templates * **API Credential Types:** Merchant * **Required Role:** Terms & Conditions Management This API returns all terms and conditions templates associated with a merchant account. ```rust use blockchyp; use std::error::Error; fn tc_templates_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TermsAndConditionsTemplateRequest{ ..Default::default() }; let (response, err) = client.tc_templates(&request); if let Some(e) = err { eprintln!("Unexpected error occurred: {:?}", e); return Err(e) } if response.success { println!("Success"); } println!("Response: {:?}", response); Ok(()) } fn main() -> Result<(), Box> { tc_templates_example()?; println!("Example completed successfully!"); Ok(()) } ``` #### Get Template * **API Credential Types:** Merchant * **Required Role:** Terms & Conditions Management This API returns as single terms and conditions template. ```rust use blockchyp; use std::error::Error; fn tc_template_example() -> Result<(), Box> { // sample credentials let creds = blockchyp::APICredentials { api_key: "ZDSMMZLGRPBPRTJUBTAFBYZ33Q".to_string(), bearer_token: "ZLBW5NR4U5PKD5PNP3ZP3OZS5U".to_string(), signing_key: "9c6a5e8e763df1c9256e3d72bd7f53dfbd07312938131c75b3bfd254da787947".to_string(), }; // instantiate the client let client = blockchyp::Client::new(creds); let request = blockchyp::TermsAndConditionsTemplateRequest{ template_id: "