{"__v":2,"_id":"57780374ea758f0e00e6f82c","api":{"auth":"never","params":[],"results":{"codes":[]},"settings":"","url":""},"body":"Two Tap allows anyone to place orders on ecommerce sites using code. \n\nTwo Tap supports regular domestic checkout, pick-up from store, and international checkout.\n\nThere are three ways of integrating Two Tap: using [**Instant**](/docs/instant) (easiest), using the [**Cart**](/docs/cart), or using the [**API**](/docs/api) (advanced).\n\nTwo Tap take the asynchronous approach to placing orders. This means Two Tap accepts a purchase and processes it in the background. The actual processing time varies on a lot of factors, usually being under 2 minutes for domestic orders, and a day for international orders. However, in rare edge cases, this can take longer.\n\nThis approach is incredibly common in the eCommerce industry. For instance, when placing an order on Amazon's website your information is accepted instantly and if it wasn't valid you receive an email five minutes later. On almost any retailer there's a 'Processing' stage that can take up to a couple of days.\n\nSimilarly, Two Tap has a processing phase that usually takes a couple of minutes in domestic orders and a day for international orders, but could end up lasting longer. Handling this behaviour via Two Tap is incredibly easy.","category":"57780374ea758f0e00e6f81e","createdAt":"2014-10-25T00:48:01.831Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"getting-started","sync_unique":"","title":"Two Tap API","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Two Tap API


Two Tap allows anyone to place orders on ecommerce sites using code. Two Tap supports regular domestic checkout, pick-up from store, and international checkout. There are three ways of integrating Two Tap: using [**Instant**](/docs/instant) (easiest), using the [**Cart**](/docs/cart), or using the [**API**](/docs/api) (advanced). Two Tap take the asynchronous approach to placing orders. This means Two Tap accepts a purchase and processes it in the background. The actual processing time varies on a lot of factors, usually being under 2 minutes for domestic orders, and a day for international orders. However, in rare edge cases, this can take longer. This approach is incredibly common in the eCommerce industry. For instance, when placing an order on Amazon's website your information is accepted instantly and if it wasn't valid you receive an email five minutes later. On almost any retailer there's a 'Processing' stage that can take up to a couple of days. Similarly, Two Tap has a processing phase that usually takes a couple of minutes in domestic orders and a day for international orders, but could end up lasting longer. Handling this behaviour via Two Tap is incredibly easy.
Two Tap allows anyone to place orders on ecommerce sites using code. Two Tap supports regular domestic checkout, pick-up from store, and international checkout. There are three ways of integrating Two Tap: using [**Instant**](/docs/instant) (easiest), using the [**Cart**](/docs/cart), or using the [**API**](/docs/api) (advanced). Two Tap take the asynchronous approach to placing orders. This means Two Tap accepts a purchase and processes it in the background. The actual processing time varies on a lot of factors, usually being under 2 minutes for domestic orders, and a day for international orders. However, in rare edge cases, this can take longer. This approach is incredibly common in the eCommerce industry. For instance, when placing an order on Amazon's website your information is accepted instantly and if it wasn't valid you receive an email five minutes later. On almost any retailer there's a 'Processing' stage that can take up to a couple of days. Similarly, Two Tap has a processing phase that usually takes a couple of minutes in domestic orders and a day for international orders, but could end up lasting longer. Handling this behaviour via Two Tap is incredibly easy.
{"__v":15,"_id":"577808255b2b430e00b98309","api":{"auth":"required","params":[],"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","url":""},"body":"In domestic and pickup-from-store orders Two Tap sends all the information to the retailer to be processed. That means the end retailer (let's say Kohls) processes the payment, handles returns, customer support, and is the merchant of record. This is what we call the pass-through method.\n\nFor international orders, this all changes. The end customer (let's say in Japan) buys the products from Two Tap, which are then, in the background, automatically purchased by Two Tap from the retailer and shipped to a US warehouse. This means Two Tap processes the consumer payment, handles returns, customer support, and is the merchant of record.\n\nFor international orders Two Tap provides more flexibility:\n  * A larger number of payment methods will be supported. For instance: Apple Pay, Android Pay. (coming soon)\n  * The CVV code will not be required after an initial purchase. (coming soon)\n  * Publisher discounts (eg. a publisher wanting to fund $10 off offers).\n  * One international landed cost for the whole cart. This price is always cheaper than buying at the stores directly as Two Tap does consolidation and sends out products in one international flight.\n  * Estimation guarantees. If Two Tap's estimation is wrong, Two Tap will eat the cost.\n  * If certain products end up being out of stock, Two Tap contacts consumers and removes the affected items to ensure purchases can still be placed successfully.\n\nHowever, there are a couple of requirements:\n  *  The international app approval process is a bit more thorough.\n  *  All apps must show the [\"Two Tap INTL ToS Approval Box\"](http://docs.twotap.com/docs/testing-api#international-tos-approval-box).\n  * Publishers wanting to promote retailers internationally have to be accepted by the stores inside the Two Tap dashboard.\n  * Commissions for international orders will be paid to publishers by Two Tap at a different rate than normal affiliate commissions. The rates are visible inside the Two Tap dashboard.\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Countries supported for international shipping\"\n}\n[/block]\nCurrently, Two Tap can send products from USA to Japan.","category":"57780374ea758f0e00e6f81e","createdAt":"2016-07-02T18:29:57.924Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":999,"project":"544af341a761f90800c41d50","slug":"domestic-vs-intl","sync_unique":"","title":"Domestic vs INTL","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Domestic vs INTL


In domestic and pickup-from-store orders Two Tap sends all the information to the retailer to be processed. That means the end retailer (let's say Kohls) processes the payment, handles returns, customer support, and is the merchant of record. This is what we call the pass-through method. For international orders, this all changes. The end customer (let's say in Japan) buys the products from Two Tap, which are then, in the background, automatically purchased by Two Tap from the retailer and shipped to a US warehouse. This means Two Tap processes the consumer payment, handles returns, customer support, and is the merchant of record. For international orders Two Tap provides more flexibility: * A larger number of payment methods will be supported. For instance: Apple Pay, Android Pay. (coming soon) * The CVV code will not be required after an initial purchase. (coming soon) * Publisher discounts (eg. a publisher wanting to fund $10 off offers). * One international landed cost for the whole cart. This price is always cheaper than buying at the stores directly as Two Tap does consolidation and sends out products in one international flight. * Estimation guarantees. If Two Tap's estimation is wrong, Two Tap will eat the cost. * If certain products end up being out of stock, Two Tap contacts consumers and removes the affected items to ensure purchases can still be placed successfully. However, there are a couple of requirements: * The international app approval process is a bit more thorough. * All apps must show the ["Two Tap INTL ToS Approval Box"](http://docs.twotap.com/docs/testing-api#international-tos-approval-box). * Publishers wanting to promote retailers internationally have to be accepted by the stores inside the Two Tap dashboard. * Commissions for international orders will be paid to publishers by Two Tap at a different rate than normal affiliate commissions. The rates are visible inside the Two Tap dashboard. [block:api-header] { "type": "basic", "title": "Countries supported for international shipping" } [/block] Currently, Two Tap can send products from USA to Japan.
In domestic and pickup-from-store orders Two Tap sends all the information to the retailer to be processed. That means the end retailer (let's say Kohls) processes the payment, handles returns, customer support, and is the merchant of record. This is what we call the pass-through method. For international orders, this all changes. The end customer (let's say in Japan) buys the products from Two Tap, which are then, in the background, automatically purchased by Two Tap from the retailer and shipped to a US warehouse. This means Two Tap processes the consumer payment, handles returns, customer support, and is the merchant of record. For international orders Two Tap provides more flexibility: * A larger number of payment methods will be supported. For instance: Apple Pay, Android Pay. (coming soon) * The CVV code will not be required after an initial purchase. (coming soon) * Publisher discounts (eg. a publisher wanting to fund $10 off offers). * One international landed cost for the whole cart. This price is always cheaper than buying at the stores directly as Two Tap does consolidation and sends out products in one international flight. * Estimation guarantees. If Two Tap's estimation is wrong, Two Tap will eat the cost. * If certain products end up being out of stock, Two Tap contacts consumers and removes the affected items to ensure purchases can still be placed successfully. However, there are a couple of requirements: * The international app approval process is a bit more thorough. * All apps must show the ["Two Tap INTL ToS Approval Box"](http://docs.twotap.com/docs/testing-api#international-tos-approval-box). * Publishers wanting to promote retailers internationally have to be accepted by the stores inside the Two Tap dashboard. * Commissions for international orders will be paid to publishers by Two Tap at a different rate than normal affiliate commissions. The rates are visible inside the Two Tap dashboard. [block:api-header] { "type": "basic", "title": "Countries supported for international shipping" } [/block] Currently, Two Tap can send products from USA to Japan.
{"__v":1,"_id":"57780374ea758f0e00e6f839","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"With Instant content creators like bloggers, magazines, and newspapers can sell products directly on their desktop and mobile websites. It's the easiest way to use Two Tap.\n\nInstant is web only (you need to use the Cart or API for native iOS/Android apps) and was designed to look good on both desktop as well as on mobile.\n\nInstant supports domestic and international checkout.\n\nInstant has two modes: [**'detect'**](/docs/detect-integration) and [**'manual'**](/docs/manual-integration).","category":"57780374ea758f0e00e6f81f","createdAt":"2015-07-13T00:43:36.087Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":1,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"instant","sync_unique":"","title":"Instant","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Instant


With Instant content creators like bloggers, magazines, and newspapers can sell products directly on their desktop and mobile websites. It's the easiest way to use Two Tap. Instant is web only (you need to use the Cart or API for native iOS/Android apps) and was designed to look good on both desktop as well as on mobile. Instant supports domestic and international checkout. Instant has two modes: [**'detect'**](/docs/detect-integration) and [**'manual'**](/docs/manual-integration).
With Instant content creators like bloggers, magazines, and newspapers can sell products directly on their desktop and mobile websites. It's the easiest way to use Two Tap. Instant is web only (you need to use the Cart or API for native iOS/Android apps) and was designed to look good on both desktop as well as on mobile. Instant supports domestic and international checkout. Instant has two modes: [**'detect'**](/docs/detect-integration) and [**'manual'**](/docs/manual-integration).
{"category":"57780374ea758f0e00e6f81f","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f83a","createdAt":"2015-07-13T00:44:32.312Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"Copy & paste the code below into your site's HTML just above the end </body> tag.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type='text/javascript'>\\n  (function() {\\n      TTPublicToken = '__YOUR_TWO_TAP_PUBLIC_TOKEN__';\\n\\n      var tt = document.createElement('script'); \\n      tt.type = 'text/javascript'; \\n      tt.async = true; \\n      tt.src = 'https://instant.twotap.com/js/publisher_cart.js'; \\n      var s = document.getElementsByTagName('script')[0];\\n      s.parentNode.insertBefore(tt, s);\\n  })();\\n</script>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"setup","type":"basic","title":"Setup","__v":0,"childrenPages":[]}

Setup


Copy & paste the code below into your site's HTML just above the end </body> tag. [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n (function() {\n TTPublicToken = '__YOUR_TWO_TAP_PUBLIC_TOKEN__';\n\n var tt = document.createElement('script'); \n tt.type = 'text/javascript'; \n tt.async = true; \n tt.src = 'https://instant.twotap.com/js/publisher_cart.js'; \n var s = document.getElementsByTagName('script')[0];\n s.parentNode.insertBefore(tt, s);\n })();\n</script>", "language": "html" } ] } [/block]
Copy & paste the code below into your site's HTML just above the end </body> tag. [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n (function() {\n TTPublicToken = '__YOUR_TWO_TAP_PUBLIC_TOKEN__';\n\n var tt = document.createElement('script'); \n tt.type = 'text/javascript'; \n tt.async = true; \n tt.src = 'https://instant.twotap.com/js/publisher_cart.js'; \n var s = document.getElementsByTagName('script')[0];\n s.parentNode.insertBefore(tt, s);\n })();\n</script>", "language": "html" } ] } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f83b","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"'detect'  looks for product links in your content. If it finds products that can be bought it pops up a button that controls a gallery and checkout.\n\nEvery time a web page is loaded possible product URLs are scanned and sent to Two Tap's servers. Two Tap then fetches product information (title, images, prices, etc), a process that can take up to 30 seconds. The next time the page is loaded if Two Tap has finished getting information the gallery button will appear.\n\n'detect' is the default mode, and Instant will take care of everything.","category":"57780374ea758f0e00e6f81f","createdAt":"2015-07-13T00:45:10.776Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":3,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"detect-integration","sync_unique":"","title":"'detect' integration","type":"basic","updates":["55d234af486de50d00326ffd","57e2d57230b3901700643979"],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

'detect' integration


'detect' looks for product links in your content. If it finds products that can be bought it pops up a button that controls a gallery and checkout. Every time a web page is loaded possible product URLs are scanned and sent to Two Tap's servers. Two Tap then fetches product information (title, images, prices, etc), a process that can take up to 30 seconds. The next time the page is loaded if Two Tap has finished getting information the gallery button will appear. 'detect' is the default mode, and Instant will take care of everything.
'detect' looks for product links in your content. If it finds products that can be bought it pops up a button that controls a gallery and checkout. Every time a web page is loaded possible product URLs are scanned and sent to Two Tap's servers. Two Tap then fetches product information (title, images, prices, etc), a process that can take up to 30 seconds. The next time the page is loaded if Two Tap has finished getting information the gallery button will appear. 'detect' is the default mode, and Instant will take care of everything.
{"category":"57780374ea758f0e00e6f81f","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f83c","createdAt":"2015-07-13T00:46:57.581Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"body":"'manual' allows you to transform your existing product links, that might redirect via affiliate marketing offsite, to an inline checkout.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type='text/javascript'>\\n  TTInstantMode = 'manual';\\n\\n  // Instant Setup code here.\\n</script>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\nInstant will look at all links that have a 'data-tt' attribute. The two possible options for 'data-tt' are 'open-gallery' or 'open-checkout'\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<a href='http://store_url/product' \\n   data-tt='open-checkout'\\n   data-tt-affiliate-link='http://affiliate_link'>\\n\\n   Buy\\n</a>\\n\\n<a href='http://store_url/product'\\n   data-tt='open-gallery'\\n   data-tt-affiliate-link='http://affiliate_link'>\\n\\n   Buy\\n</a>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\nYou can send multiple product urls like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<a href='#' \\n   data-tt='open-gallery' \\n   data-tt-product-link-1='http://product' \\n   data-tt-affiliate-link-1='http://affiliate'\\n   data-tt-product-link-2='http://product'\\n   data-tt-affiliate-link-2='http://affiliate'>\\n\\n   Buy\\n</a>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"manual-integration","type":"basic","title":"'manual' integration","__v":0,"childrenPages":[]}

'manual' integration


'manual' allows you to transform your existing product links, that might redirect via affiliate marketing offsite, to an inline checkout. [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n TTInstantMode = 'manual';\n\n // Instant Setup code here.\n</script>", "language": "html" } ] } [/block] Instant will look at all links that have a 'data-tt' attribute. The two possible options for 'data-tt' are 'open-gallery' or 'open-checkout' [block:code] { "codes": [ { "code": "<a href='http://store_url/product' \n data-tt='open-checkout'\n data-tt-affiliate-link='http://affiliate_link'>\n\n Buy\n</a>\n\n<a href='http://store_url/product'\n data-tt='open-gallery'\n data-tt-affiliate-link='http://affiliate_link'>\n\n Buy\n</a>", "language": "html" } ] } [/block] You can send multiple product urls like this: [block:code] { "codes": [ { "code": "<a href='#' \n data-tt='open-gallery' \n data-tt-product-link-1='http://product' \n data-tt-affiliate-link-1='http://affiliate'\n data-tt-product-link-2='http://product'\n data-tt-affiliate-link-2='http://affiliate'>\n\n Buy\n</a>", "language": "html" } ] } [/block]
'manual' allows you to transform your existing product links, that might redirect via affiliate marketing offsite, to an inline checkout. [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n TTInstantMode = 'manual';\n\n // Instant Setup code here.\n</script>", "language": "html" } ] } [/block] Instant will look at all links that have a 'data-tt' attribute. The two possible options for 'data-tt' are 'open-gallery' or 'open-checkout' [block:code] { "codes": [ { "code": "<a href='http://store_url/product' \n data-tt='open-checkout'\n data-tt-affiliate-link='http://affiliate_link'>\n\n Buy\n</a>\n\n<a href='http://store_url/product'\n data-tt='open-gallery'\n data-tt-affiliate-link='http://affiliate_link'>\n\n Buy\n</a>", "language": "html" } ] } [/block] You can send multiple product urls like this: [block:code] { "codes": [ { "code": "<a href='#' \n data-tt='open-gallery' \n data-tt-product-link-1='http://product' \n data-tt-affiliate-link-1='http://affiliate'\n data-tt-product-link-2='http://product'\n data-tt-affiliate-link-2='http://affiliate'>\n\n Buy\n</a>", "language": "html" } ] } [/block]
{"category":"57780374ea758f0e00e6f81f","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f83d","createdAt":"2015-07-13T01:39:12.725Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"After you add the code on the first page load it might appear that Instant isn't doing anything. That's because we scan all the product URLs and fetch information about them in the background. As soon as that process ends (which depends on the number of products, but is usually under a minute), the gallery/checkout functionality will be activated.\n\nTo see what Instant does in the background we've added a simple to use toggle. Append tt-debug=true to your page's URL and Instant will show you a message with what's happening.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/xjRQoo2mQFeTY42MbWEB_simple-debug-url.png\",\n        \"simple-debug-url.png\",\n        \"1162\",\n        \"118\",\n        \"#ec4c5c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe message will look something like below.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/5UFOlwkQlihyxNHTqcSw_simple-debug-example.png\",\n        \"simple-debug-example.png\",\n        \"944\",\n        \"406\",\n        \"#e84e5d\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"testing-instant","type":"basic","title":"Testing","__v":0,"childrenPages":[]}

Testing


After you add the code on the first page load it might appear that Instant isn't doing anything. That's because we scan all the product URLs and fetch information about them in the background. As soon as that process ends (which depends on the number of products, but is usually under a minute), the gallery/checkout functionality will be activated. To see what Instant does in the background we've added a simple to use toggle. Append tt-debug=true to your page's URL and Instant will show you a message with what's happening. [block:image] { "images": [ { "image": [ "https://files.readme.io/xjRQoo2mQFeTY42MbWEB_simple-debug-url.png", "simple-debug-url.png", "1162", "118", "#ec4c5c", "" ] } ] } [/block] The message will look something like below. [block:image] { "images": [ { "image": [ "https://files.readme.io/5UFOlwkQlihyxNHTqcSw_simple-debug-example.png", "simple-debug-example.png", "944", "406", "#e84e5d", "" ] } ] } [/block]
After you add the code on the first page load it might appear that Instant isn't doing anything. That's because we scan all the product URLs and fetch information about them in the background. As soon as that process ends (which depends on the number of products, but is usually under a minute), the gallery/checkout functionality will be activated. To see what Instant does in the background we've added a simple to use toggle. Append tt-debug=true to your page's URL and Instant will show you a message with what's happening. [block:image] { "images": [ { "image": [ "https://files.readme.io/xjRQoo2mQFeTY42MbWEB_simple-debug-url.png", "simple-debug-url.png", "1162", "118", "#ec4c5c", "" ] } ] } [/block] The message will look something like below. [block:image] { "images": [ { "image": [ "https://files.readme.io/5UFOlwkQlihyxNHTqcSw_simple-debug-example.png", "simple-debug-example.png", "944", "406", "#e84e5d", "" ] } ] } [/block]
{"__v":2,"_id":"57780374ea758f0e00e6f83e","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"TTPublicToken\",\n    \"0-1\": \"Your public token.\",\n    \"1-0\": \"TTCustomCSSURL\",\n    \"1-1\": \"(Optional) You can customize the look & feel of Instant by using CSS. Include a https:// link to a CSS file.\",\n    \"2-0\": \"TTConfirm\",\n    \"2-1\": \"(Optional) A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\\n\\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }\\n\\nor\\n\\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }\",\n    \"5-0\": \"TTViglinkApiKey\",\n    \"5-1\": \"(Optional) If you are using Viglink add your key here and Instant will automatically create the affiliate links for you.\",\n    \"4-0\": \"TTUniqueToken\",\n    \"4-1\": \"(Optional) An unique token that will be sent with the purchase confirm callbacks.\",\n    \"3-0\": \"TTCacheTime\",\n    \"3-1\": \"(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).\",\n    \"6-0\": \"TTDestinationCountry\",\n    \"6-1\": \"(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country.\"\n  },\n  \"cols\": 2,\n  \"rows\": 7\n}\n[/block]","category":"57780374ea758f0e00e6f81f","createdAt":"2015-07-13T00:48:46.294Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":6,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"options","sync_unique":"","title":"Options","type":"basic","updates":["566110cdf5a87e0d00db31a7"],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Options


[block:parameters] { "data": { "0-0": "TTPublicToken", "0-1": "Your public token.", "1-0": "TTCustomCSSURL", "1-1": "(Optional) You can customize the look & feel of Instant by using CSS. Include a https:// link to a CSS file.", "2-0": "TTConfirm", "2-1": "(Optional) A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\n\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }\n\nor\n\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }", "5-0": "TTViglinkApiKey", "5-1": "(Optional) If you are using Viglink add your key here and Instant will automatically create the affiliate links for you.", "4-0": "TTUniqueToken", "4-1": "(Optional) An unique token that will be sent with the purchase confirm callbacks.", "3-0": "TTCacheTime", "3-1": "(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).", "6-0": "TTDestinationCountry", "6-1": "(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country." }, "cols": 2, "rows": 7 } [/block]
[block:parameters] { "data": { "0-0": "TTPublicToken", "0-1": "Your public token.", "1-0": "TTCustomCSSURL", "1-1": "(Optional) You can customize the look & feel of Instant by using CSS. Include a https:// link to a CSS file.", "2-0": "TTConfirm", "2-1": "(Optional) A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\n\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }\n\nor\n\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }", "5-0": "TTViglinkApiKey", "5-1": "(Optional) If you are using Viglink add your key here and Instant will automatically create the affiliate links for you.", "4-0": "TTUniqueToken", "4-1": "(Optional) An unique token that will be sent with the purchase confirm callbacks.", "3-0": "TTCacheTime", "3-1": "(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).", "6-0": "TTDestinationCountry", "6-1": "(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country." }, "cols": 2, "rows": 7 } [/block]
{"category":"57780374ea758f0e00e6f81f","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f83f","createdAt":"2015-07-13T00:47:26.938Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"[block:parameters]\n{\n  \"data\": {\n    \"1-0\": \"TTRefresh()\",\n    \"1-1\": \"Instant reloads itself. This is useful if you are retrieving products via AJAX.\",\n    \"0-0\": \"TTStartCheckout(products)\",\n    \"0-1\": \"Use this to manually start a checkout with a list of products. Accepts an array of hashes like:\\n\\n[ { url: productURL, affiliate_link: affiliateLink } ]\"\n  },\n  \"cols\": 2,\n  \"rows\": 2\n}\n[/block]","excerpt":"","slug":"methods","type":"basic","title":"Methods","__v":0,"childrenPages":[]}

Methods


[block:parameters] { "data": { "1-0": "TTRefresh()", "1-1": "Instant reloads itself. This is useful if you are retrieving products via AJAX.", "0-0": "TTStartCheckout(products)", "0-1": "Use this to manually start a checkout with a list of products. Accepts an array of hashes like:\n\n[ { url: productURL, affiliate_link: affiliateLink } ]" }, "cols": 2, "rows": 2 } [/block]
[block:parameters] { "data": { "1-0": "TTRefresh()", "1-1": "Instant reloads itself. This is useful if you are retrieving products via AJAX.", "0-0": "TTStartCheckout(products)", "0-1": "Use this to manually start a checkout with a list of products. Accepts an array of hashes like:\n\n[ { url: productURL, affiliate_link: affiliateLink } ]" }, "cols": 2, "rows": 2 } [/block]
{"category":"57780374ea758f0e00e6f81f","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f840","createdAt":"2015-07-13T00:48:22.756Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"[block:parameters]\n{\n  \"data\": {\n    \"1-0\": \"TTAttachedToLinkCallback(link)\",\n    \"1-1\": \"(Optional) In manual mode this method will be called once Instant attaches itself to a link.\",\n    \"2-1\": \"(Optional) In manual mode this method will be called when Instant fails to attach itself to a link with 'data-tt' set.\",\n    \"2-0\": \"TTFailedToAttachToLinkCallback(link)\",\n    \"0-0\": \"TTLoadedCallback()\",\n    \"0-1\": \"(Optional) Called after the Instant script was loaded on the page.\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]","excerpt":"","slug":"callbacks","type":"basic","title":"Callbacks","__v":0,"childrenPages":[]}

Callbacks


[block:parameters] { "data": { "1-0": "TTAttachedToLinkCallback(link)", "1-1": "(Optional) In manual mode this method will be called once Instant attaches itself to a link.", "2-1": "(Optional) In manual mode this method will be called when Instant fails to attach itself to a link with 'data-tt' set.", "2-0": "TTFailedToAttachToLinkCallback(link)", "0-0": "TTLoadedCallback()", "0-1": "(Optional) Called after the Instant script was loaded on the page." }, "cols": 2, "rows": 3 } [/block]
[block:parameters] { "data": { "1-0": "TTAttachedToLinkCallback(link)", "1-1": "(Optional) In manual mode this method will be called once Instant attaches itself to a link.", "2-1": "(Optional) In manual mode this method will be called when Instant fails to attach itself to a link with 'data-tt' set.", "2-0": "TTFailedToAttachToLinkCallback(link)", "0-0": "TTLoadedCallback()", "0-1": "(Optional) Called after the Instant script was loaded on the page." }, "cols": 2, "rows": 3 } [/block]
{"category":"57780374ea758f0e00e6f820","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f82d","createdAt":"2015-02-12T04:19:49.506Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":9,"body":"The Cart HTML5 interface is a pre-created checkout interface on top of our API. It's completely white label and designed as mobile-first.\n\nTo use it just point a web browser, a UIWebView (iOS), or a WebView (Android) to https://checkout.twotap.com with a pre-created checkout_request.\n\nThe Cart will call the confirm_url with the unique_token and a purchase_id to ask for the final order confirmation. More information about this below.\n\nThe Cart interface is stateless, which means you can't add products to an existing cart. For multi-products / multi-retailers we recommend you store the list of product URLs locally (localstorage, NSUserDefaults), and open the interface once the users presses your checkout button. You don't have to do any extra UI work since you would have a 'checkout' button (that contains a count of products in the cart) anyways. When shoppers press that button pass us that array of product URLs.","excerpt":"","slug":"cart-html5","type":"basic","title":"Cart Interface","__v":0,"childrenPages":[]}

Cart Interface


The Cart HTML5 interface is a pre-created checkout interface on top of our API. It's completely white label and designed as mobile-first. To use it just point a web browser, a UIWebView (iOS), or a WebView (Android) to https://checkout.twotap.com with a pre-created checkout_request. The Cart will call the confirm_url with the unique_token and a purchase_id to ask for the final order confirmation. More information about this below. The Cart interface is stateless, which means you can't add products to an existing cart. For multi-products / multi-retailers we recommend you store the list of product URLs locally (localstorage, NSUserDefaults), and open the interface once the users presses your checkout button. You don't have to do any extra UI work since you would have a 'checkout' button (that contains a count of products in the cart) anyways. When shoppers press that button pass us that array of product URLs.
The Cart HTML5 interface is a pre-created checkout interface on top of our API. It's completely white label and designed as mobile-first. To use it just point a web browser, a UIWebView (iOS), or a WebView (Android) to https://checkout.twotap.com with a pre-created checkout_request. The Cart will call the confirm_url with the unique_token and a purchase_id to ask for the final order confirmation. More information about this below. The Cart interface is stateless, which means you can't add products to an existing cart. For multi-products / multi-retailers we recommend you store the list of product URLs locally (localstorage, NSUserDefaults), and open the interface once the users presses your checkout button. You don't have to do any extra UI work since you would have a 'checkout' button (that contains a count of products in the cart) anyways. When shoppers press that button pass us that array of product URLs.
{"__v":3,"_id":"57780374ea758f0e00e6f82e","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"Below you can find an example of how to open the Cart on the web.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Start by making a POST request to:\\n// https://checkout.twotap.com/prepare_checkout\\n\\nvar checkoutRequest = {};\\ncheckoutRequest['products'] = [ { url: 'http://www.nastygal.com/clothes-dresses/reverse-havana-lace-dress--black' } ];\\ncheckoutRequest['public_token'] = '<%- publicToken %>';\\ncheckoutRequest['custom_css_url'] = '<%- customCSSURL %>';\\ncheckoutRequest['confirm'] = { method: 'sms', sms_confirm_url: '<%- smsConfirmURL %>' }\\ncheckoutRequest['unique_token'] = (Math.floor(Math.random() * 9999999) + 1).toString();\\n\\njQuery.post('https://checkout.twotap.com/prepare_checkout', { checkout_request: checkoutRequest }, function(data) {\\n  // This will return a hash like:\\n  // {\\n  //   \\\"message\\\":\\\"done\\\",\\n  //   \\\"checkout_request_id\\\":\\\"7E9N560S85THFDMlt85UBgWVZqCSfv\\\",\\n  //   \\\"url\\\":\\\"https://checkout.twotap.com/?checkout_request_id=7E9N560S85THFDMlt85UBgWVZqCSfv\\\"\\n  // }\\n  \\n  // Point an iFrame to that URL.\\n  $('#ttIframe').attr('src', data['url']);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"/prepare_checkout allowed arguments\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"public_token\",\n    \"0-1\": \"The public token from your Two Tap developer interface.\",\n    \"2-0\": \"confirm\",\n    \"2-1\": \"A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\\n\\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }.\\n\\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }.\\n\\nFor more information see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow).\\n\\nTransform this object into JSON before sending it.\",\n    \"3-0\": \"products\",\n    \"3-1\": \"An array of hashes like:\\n\\n[ { 'url': 'the product url', 'affiliate_link': '(Optional) an affiliate link', 'input_fields': '(Optional) a hash of product values, ex: { 'quantity': '2' }.' } ].\\n\\nTransform this object into JSON before sending it. Max 15 products in one session.\",\n    \"4-0\": \"input_fields\",\n    \"4-1\": \"(Optional) If you want to prefill information about the user/purchase you can send the values. Send a hash like:\\n\\n{ 'shipping_state': 'California', 'coupons': { site_id: 'coupon_value' } }.\\n\\nTransform this object into JSON before sending it.\",\n    \"5-0\": \"test_mode\",\n    \"5-1\": \"(Optional) fake_confirm. A way to test the interface without making actual purchases.\",\n    \"6-0\": \"custom_css_url\",\n    \"6-1\": \"(Optional) An url to your custom css file. Has to be served over https.\",\n    \"7-0\": \"close_button\",\n    \"7-1\": \"(Optional) Add hash like below if you want a close button on the top right side of the interface. You don't need to specify an action. By default it will send a postMessage that you can catch and handle on both desktop and iOS.\\n\\n{ show: 'true', action: (optional)'redirect', url: (optional)'http://where-to-redirect_to' }\",\n    \"9-0\": \"retry_url\",\n    \"9-1\": \"(Optional) In case of failures (like payment issues) shoppers receive an SMS with a link to retry the purchase. By default this restarts the checkout in Safari, however you can tweak the retry_url to send them back to your app. See the 'Restarting purchases' section below.\",\n    \"10-0\": \"top_banner\",\n    \"10-1\": \"(Optional) Add hash like below if you want a banner at the top of the interface:\\n\\n{ 'standard_message': 'message', 'standard_url': 'url', 'success_message': 'message', 'success_url': 'url' }.\\n\\nThis is useful in case you want a custom back button or need to display a message.\\n\\nAt the end of the checkout process the interface will set the banner with the values of success_*.\",\n    \"1-0\": \"unique_token\",\n    \"1-1\": \"An unique token generated by you that is sent back with the confirm url call.\",\n    \"11-0\": \"notes\",\n    \"11-1\": \"(Optional) You can send any information here as a hash and it will be attached to carts/purchases and piped back with /status responses and callbacks.\",\n    \"8-0\": \"wallet\",\n    \"8-1\": \"(optional) \\n\\nSend 'default_off' if you want to set the 'Save checkout info for future use' toggle as off by default. \\n\\nSend 'off' to disable the wallet completely.\",\n    \"12-0\": \"cache_time\",\n    \"12-1\": \"(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).\",\n    \"13-0\": \"destination_country\",\n    \"13-1\": \"(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country.\"\n  },\n  \"cols\": 2,\n  \"rows\": 14\n}\n[/block]","category":"57780374ea758f0e00e6f820","createdAt":"2015-02-12T04:23:38.939Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":10,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"opening-via-post","sync_unique":"","title":"Opening the Cart","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Opening the Cart


Below you can find an example of how to open the Cart on the web. [block:code] { "codes": [ { "code": "// Start by making a POST request to:\n// https://checkout.twotap.com/prepare_checkout\n\nvar checkoutRequest = {};\ncheckoutRequest['products'] = [ { url: 'http://www.nastygal.com/clothes-dresses/reverse-havana-lace-dress--black' } ];\ncheckoutRequest['public_token'] = '<%- publicToken %>';\ncheckoutRequest['custom_css_url'] = '<%- customCSSURL %>';\ncheckoutRequest['confirm'] = { method: 'sms', sms_confirm_url: '<%- smsConfirmURL %>' }\ncheckoutRequest['unique_token'] = (Math.floor(Math.random() * 9999999) + 1).toString();\n\njQuery.post('https://checkout.twotap.com/prepare_checkout', { checkout_request: checkoutRequest }, function(data) {\n // This will return a hash like:\n // {\n // \"message\":\"done\",\n // \"checkout_request_id\":\"7E9N560S85THFDMlt85UBgWVZqCSfv\",\n // \"url\":\"https://checkout.twotap.com/?checkout_request_id=7E9N560S85THFDMlt85UBgWVZqCSfv\"\n // }\n \n // Point an iFrame to that URL.\n $('#ttIframe').attr('src', data['url']);\n});", "language": "javascript" } ] } [/block] [block:api-header] { "type": "basic", "title": "/prepare_checkout allowed arguments" } [/block] [block:parameters] { "data": { "0-0": "public_token", "0-1": "The public token from your Two Tap developer interface.", "2-0": "confirm", "2-1": "A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\n\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }.\n\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }.\n\nFor more information see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow).\n\nTransform this object into JSON before sending it.", "3-0": "products", "3-1": "An array of hashes like:\n\n[ { 'url': 'the product url', 'affiliate_link': '(Optional) an affiliate link', 'input_fields': '(Optional) a hash of product values, ex: { 'quantity': '2' }.' } ].\n\nTransform this object into JSON before sending it. Max 15 products in one session.", "4-0": "input_fields", "4-1": "(Optional) If you want to prefill information about the user/purchase you can send the values. Send a hash like:\n\n{ 'shipping_state': 'California', 'coupons': { site_id: 'coupon_value' } }.\n\nTransform this object into JSON before sending it.", "5-0": "test_mode", "5-1": "(Optional) fake_confirm. A way to test the interface without making actual purchases.", "6-0": "custom_css_url", "6-1": "(Optional) An url to your custom css file. Has to be served over https.", "7-0": "close_button", "7-1": "(Optional) Add hash like below if you want a close button on the top right side of the interface. You don't need to specify an action. By default it will send a postMessage that you can catch and handle on both desktop and iOS.\n\n{ show: 'true', action: (optional)'redirect', url: (optional)'http://where-to-redirect_to' }", "9-0": "retry_url", "9-1": "(Optional) In case of failures (like payment issues) shoppers receive an SMS with a link to retry the purchase. By default this restarts the checkout in Safari, however you can tweak the retry_url to send them back to your app. See the 'Restarting purchases' section below.", "10-0": "top_banner", "10-1": "(Optional) Add hash like below if you want a banner at the top of the interface:\n\n{ 'standard_message': 'message', 'standard_url': 'url', 'success_message': 'message', 'success_url': 'url' }.\n\nThis is useful in case you want a custom back button or need to display a message.\n\nAt the end of the checkout process the interface will set the banner with the values of success_*.", "1-0": "unique_token", "1-1": "An unique token generated by you that is sent back with the confirm url call.", "11-0": "notes", "11-1": "(Optional) You can send any information here as a hash and it will be attached to carts/purchases and piped back with /status responses and callbacks.", "8-0": "wallet", "8-1": "(optional) \n\nSend 'default_off' if you want to set the 'Save checkout info for future use' toggle as off by default. \n\nSend 'off' to disable the wallet completely.", "12-0": "cache_time", "12-1": "(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).", "13-0": "destination_country", "13-1": "(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country." }, "cols": 2, "rows": 14 } [/block]
Below you can find an example of how to open the Cart on the web. [block:code] { "codes": [ { "code": "// Start by making a POST request to:\n// https://checkout.twotap.com/prepare_checkout\n\nvar checkoutRequest = {};\ncheckoutRequest['products'] = [ { url: 'http://www.nastygal.com/clothes-dresses/reverse-havana-lace-dress--black' } ];\ncheckoutRequest['public_token'] = '<%- publicToken %>';\ncheckoutRequest['custom_css_url'] = '<%- customCSSURL %>';\ncheckoutRequest['confirm'] = { method: 'sms', sms_confirm_url: '<%- smsConfirmURL %>' }\ncheckoutRequest['unique_token'] = (Math.floor(Math.random() * 9999999) + 1).toString();\n\njQuery.post('https://checkout.twotap.com/prepare_checkout', { checkout_request: checkoutRequest }, function(data) {\n // This will return a hash like:\n // {\n // \"message\":\"done\",\n // \"checkout_request_id\":\"7E9N560S85THFDMlt85UBgWVZqCSfv\",\n // \"url\":\"https://checkout.twotap.com/?checkout_request_id=7E9N560S85THFDMlt85UBgWVZqCSfv\"\n // }\n \n // Point an iFrame to that URL.\n $('#ttIframe').attr('src', data['url']);\n});", "language": "javascript" } ] } [/block] [block:api-header] { "type": "basic", "title": "/prepare_checkout allowed arguments" } [/block] [block:parameters] { "data": { "0-0": "public_token", "0-1": "The public token from your Two Tap developer interface.", "2-0": "confirm", "2-1": "A hash that tells the checkout interface which API flow to use. Only ports 80 (http) and 443 (https) are allowed for outbound connections. We recommend the SMS flow for ease of use.\n\n{ method: 'sms', sms_confirm_url: 'http(s)://your_endpoint', sms_update_url: 'http(s)://your_endpoint (optional)' }.\n\n{ method: 'http', http_confirm_url: 'http(s)://your_endpoint', http_update_url: 'http(s)://your_endpoint' }.\n\nFor more information see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow).\n\nTransform this object into JSON before sending it.", "3-0": "products", "3-1": "An array of hashes like:\n\n[ { 'url': 'the product url', 'affiliate_link': '(Optional) an affiliate link', 'input_fields': '(Optional) a hash of product values, ex: { 'quantity': '2' }.' } ].\n\nTransform this object into JSON before sending it. Max 15 products in one session.", "4-0": "input_fields", "4-1": "(Optional) If you want to prefill information about the user/purchase you can send the values. Send a hash like:\n\n{ 'shipping_state': 'California', 'coupons': { site_id: 'coupon_value' } }.\n\nTransform this object into JSON before sending it.", "5-0": "test_mode", "5-1": "(Optional) fake_confirm. A way to test the interface without making actual purchases.", "6-0": "custom_css_url", "6-1": "(Optional) An url to your custom css file. Has to be served over https.", "7-0": "close_button", "7-1": "(Optional) Add hash like below if you want a close button on the top right side of the interface. You don't need to specify an action. By default it will send a postMessage that you can catch and handle on both desktop and iOS.\n\n{ show: 'true', action: (optional)'redirect', url: (optional)'http://where-to-redirect_to' }", "9-0": "retry_url", "9-1": "(Optional) In case of failures (like payment issues) shoppers receive an SMS with a link to retry the purchase. By default this restarts the checkout in Safari, however you can tweak the retry_url to send them back to your app. See the 'Restarting purchases' section below.", "10-0": "top_banner", "10-1": "(Optional) Add hash like below if you want a banner at the top of the interface:\n\n{ 'standard_message': 'message', 'standard_url': 'url', 'success_message': 'message', 'success_url': 'url' }.\n\nThis is useful in case you want a custom back button or need to display a message.\n\nAt the end of the checkout process the interface will set the banner with the values of success_*.", "1-0": "unique_token", "1-1": "An unique token generated by you that is sent back with the confirm url call.", "11-0": "notes", "11-1": "(Optional) You can send any information here as a hash and it will be attached to carts/purchases and piped back with /status responses and callbacks.", "8-0": "wallet", "8-1": "(optional) \n\nSend 'default_off' if you want to set the 'Save checkout info for future use' toggle as off by default. \n\nSend 'off' to disable the wallet completely.", "12-0": "cache_time", "12-1": "(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds. Default 300 (5 minutes).", "13-0": "destination_country", "13-1": "(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country." }, "cols": 2, "rows": 14 } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f82f","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token.\n\nCallbacks are also a convenient way of storing important information about the purchase on your end.\n\nDepending on what confirm mode you are using (the default mode is SMS), see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow) confirm flows, with example code on how to implement the callbacks.\n\nWe provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"bash  <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\n**Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders.**\n\nOnce everything is set up try placing an order with test_mode=fake_confirm.\n\nIn 'fake_confirm' test mode the HTML5 interface will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors.\"\n}\n[/block]\n\nIf you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/).\n\nThere is one test mode available:  fake_confirm.\n\n**fake_confirm**\n\nIn the fake_confirm test mode the Cart interface will go through the purchase as usual, except at the final 'Purchase Confirm' step where the system will return a fake OK and not place the order.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"It's important to note that stores validate payment information when the order is actually placed, consequently store data errors (like card not valid) can appear in the last step which are going to be ignored.\"\n}\n[/block]","category":"57780374ea758f0e00e6f820","createdAt":"2015-03-15T02:29:30.939Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":11,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"testing-cart","sync_unique":"","title":"Testing","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Testing


The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token. Callbacks are also a convenient way of storing important information about the purchase on your end. Depending on what confirm mode you are using (the default mode is SMS), see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow) confirm flows, with example code on how to implement the callbacks. We provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet: [block:code] { "codes": [ { "code": "bash <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK", "language": "curl" } ] } [/block] **Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders.** Once everything is set up try placing an order with test_mode=fake_confirm. In 'fake_confirm' test mode the HTML5 interface will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order. [block:callout] { "type": "info", "body": "It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors." } [/block] If you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/). There is one test mode available: fake_confirm. **fake_confirm** In the fake_confirm test mode the Cart interface will go through the purchase as usual, except at the final 'Purchase Confirm' step where the system will return a fake OK and not place the order. [block:callout] { "type": "info", "body": "It's important to note that stores validate payment information when the order is actually placed, consequently store data errors (like card not valid) can appear in the last step which are going to be ignored." } [/block]
The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token. Callbacks are also a convenient way of storing important information about the purchase on your end. Depending on what confirm mode you are using (the default mode is SMS), see the [SMS flow](/docs/sms-checkout-flow) or [HTTP flow](/docs/http-checkout-flow) confirm flows, with example code on how to implement the callbacks. We provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet: [block:code] { "codes": [ { "code": "bash <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK", "language": "curl" } ] } [/block] **Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders.** Once everything is set up try placing an order with test_mode=fake_confirm. In 'fake_confirm' test mode the HTML5 interface will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order. [block:callout] { "type": "info", "body": "It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors." } [/block] If you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/). There is one test mode available: fake_confirm. **fake_confirm** In the fake_confirm test mode the Cart interface will go through the purchase as usual, except at the final 'Purchase Confirm' step where the system will return a fake OK and not place the order. [block:callout] { "type": "info", "body": "It's important to note that stores validate payment information when the order is actually placed, consequently store data errors (like card not valid) can appear in the last step which are going to be ignored." } [/block]
{"category":"57780374ea758f0e00e6f820","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f830","createdAt":"2015-03-15T02:32:30.659Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":12,"body":"We provide a very simple skeleton example for a desktop website integrating the Cart interface in [this github repository](https://github.com/two-tap/two-tap-backend-example).\n[block:embed]\n{\n  \"html\": \"<iframe class=\\\"embedly-embed\\\" src=\\\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554831&url=https%3A%2F%2Fvimeo.com%2F91554831&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470974287_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\\\" width=\\\"640\\\" height=\\\"400\\\" scrolling=\\\"no\\\" frameborder=\\\"0\\\" allowfullscreen></iframe>\",\n  \"url\": \"https://vimeo.com/91554831\",\n  \"title\": \"Two Tap Web Example\",\n  \"favicon\": \"https://f.vimeocdn.com/images_v6/favicon_32.ico\",\n  \"image\": \"http://i.vimeocdn.com/video/470974287_640.jpg\"\n}\n[/block]","excerpt":"","slug":"web-integration-example","type":"basic","title":"Web Example","__v":0,"childrenPages":[]}

Web Example


We provide a very simple skeleton example for a desktop website integrating the Cart interface in [this github repository](https://github.com/two-tap/two-tap-backend-example). [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554831&url=https%3A%2F%2Fvimeo.com%2F91554831&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470974287_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\" width=\"640\" height=\"400\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://vimeo.com/91554831", "title": "Two Tap Web Example", "favicon": "https://f.vimeocdn.com/images_v6/favicon_32.ico", "image": "http://i.vimeocdn.com/video/470974287_640.jpg" } [/block]
We provide a very simple skeleton example for a desktop website integrating the Cart interface in [this github repository](https://github.com/two-tap/two-tap-backend-example). [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554831&url=https%3A%2F%2Fvimeo.com%2F91554831&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470974287_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\" width=\"640\" height=\"400\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://vimeo.com/91554831", "title": "Two Tap Web Example", "favicon": "https://f.vimeocdn.com/images_v6/favicon_32.ico", "image": "http://i.vimeocdn.com/video/470974287_640.jpg" } [/block]
{"category":"57780374ea758f0e00e6f820","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f831","createdAt":"2015-03-15T02:37:03.374Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":13,"body":"We provide a couple skeleton examples for integrating the Cart interface in an iOS app.\n\nThere's an [Objective-C](https://github.com/two-tap/two-tap-ios-objective-c-example) version and a [Swift](https://github.com/two-tap/two-tap-ios-swift-example) one.\n[block:embed]\n{\n  \"html\": \"<iframe class=\\\"embedly-embed\\\" src=\\\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554020&url=https%3A%2F%2Fvimeo.com%2F91554020&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470991550_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\\\" width=\\\"640\\\" height=\\\"400\\\" scrolling=\\\"no\\\" frameborder=\\\"0\\\" allowfullscreen></iframe>\",\n  \"url\": \"https://vimeo.com/91554020\",\n  \"title\": \"Two Tap iOS Example\",\n  \"favicon\": \"https://f.vimeocdn.com/images_v6/favicon_32.ico\",\n  \"image\": \"http://i.vimeocdn.com/video/470991550_640.jpg\"\n}\n[/block]","excerpt":"","slug":"ios-integration-example","type":"basic","title":"iOS Example","__v":0,"childrenPages":[]}

iOS Example


We provide a couple skeleton examples for integrating the Cart interface in an iOS app. There's an [Objective-C](https://github.com/two-tap/two-tap-ios-objective-c-example) version and a [Swift](https://github.com/two-tap/two-tap-ios-swift-example) one. [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554020&url=https%3A%2F%2Fvimeo.com%2F91554020&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470991550_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\" width=\"640\" height=\"400\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://vimeo.com/91554020", "title": "Two Tap iOS Example", "favicon": "https://f.vimeocdn.com/images_v6/favicon_32.ico", "image": "http://i.vimeocdn.com/video/470991550_640.jpg" } [/block]
We provide a couple skeleton examples for integrating the Cart interface in an iOS app. There's an [Objective-C](https://github.com/two-tap/two-tap-ios-objective-c-example) version and a [Swift](https://github.com/two-tap/two-tap-ios-swift-example) one. [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F91554020&url=https%3A%2F%2Fvimeo.com%2F91554020&image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F470991550_640.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=vimeo\" width=\"640\" height=\"400\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://vimeo.com/91554020", "title": "Two Tap iOS Example", "favicon": "https://f.vimeocdn.com/images_v6/favicon_32.ico", "image": "http://i.vimeocdn.com/video/470991550_640.jpg" } [/block]
{"category":"57780374ea758f0e00e6f820","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f832","createdAt":"2015-07-10T21:10:33.970Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":14,"body":"Two Tap fires certain postMessage events during the purchase flow. The object is a hash that looks like: { action: Action, various_args }. On Internet Explorer 9 or earlier the object is a JSON encoded string.\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Action\",\n    \"h-1\": \"Returns\",\n    \"h-2\": \"Description\",\n    \"0-0\": \"cart_contents_changed\",\n    \"1-0\": \"cart_finalized\",\n    \"2-0\": \"close_pressed\",\n    \"0-1\": \"cart_contents, cart_event, cart_id\",\n    \"0-2\": \"This event fires anytime a cart is changed or when a purchase has been completed successfully.\\ncart_contents looks like { siteId: { productMD5: { title, image, price, url, original_url, required_fields, required_field_values, fields_input } } }\\ncart_event can be 'cart_loaded', 'product_removed', 'product_attributes_updated', or 'cart_finalized'.\",\n    \"1-2\": \"This event fires anytime a purchase has completed successfully.\",\n    \"2-2\": \"This event fires if the user presses the close button (see the show_close_button parameter).\"\n  },\n  \"cols\": 3,\n  \"rows\": 3\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"iOS\"\n}\n[/block]\nWe provide a couple of helper functions that you can use in your iOS workflow to catch events.\n\nYou can use the stringByEvaluatingJavaScriptFromString: function to run them.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@\\\"currentCartJSON()\\\"];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Function\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"currentCartJSON()\",\n    \"1-0\": \"postMessagesJSON()\",\n    \"0-1\": \"Returns the current updated cart in JSON form. On a finalized purchase the result will be empty.\\nThe hash format is { siteId: { productMD5: { title, image, price } } }\",\n    \"1-1\": \"The checkout interface triggers postMessages alerts. Since it's impossible to push these updates on mobile devices postMessagesJSON() can be polled periodically to retrieve what's being sent.\"\n  },\n  \"cols\": 2,\n  \"rows\": 2\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Web\"\n}\n[/block]\nOn the web you can catch events from outside the checkout iframe like below.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"function TTHandleEvents(event) {\\n  if (event.data['action'] == 'close_pressed') {\\n    ...\\n  }\\n}\\n\\nwindow.addEventListener('message', TTHandleEvents, false);\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"events","type":"basic","title":"Events","__v":0,"childrenPages":[]}

Events


Two Tap fires certain postMessage events during the purchase flow. The object is a hash that looks like: { action: Action, various_args }. On Internet Explorer 9 or earlier the object is a JSON encoded string. [block:parameters] { "data": { "h-0": "Action", "h-1": "Returns", "h-2": "Description", "0-0": "cart_contents_changed", "1-0": "cart_finalized", "2-0": "close_pressed", "0-1": "cart_contents, cart_event, cart_id", "0-2": "This event fires anytime a cart is changed or when a purchase has been completed successfully.\ncart_contents looks like { siteId: { productMD5: { title, image, price, url, original_url, required_fields, required_field_values, fields_input } } }\ncart_event can be 'cart_loaded', 'product_removed', 'product_attributes_updated', or 'cart_finalized'.", "1-2": "This event fires anytime a purchase has completed successfully.", "2-2": "This event fires if the user presses the close button (see the show_close_button parameter)." }, "cols": 3, "rows": 3 } [/block] [block:api-header] { "type": "basic", "title": "iOS" } [/block] We provide a couple of helper functions that you can use in your iOS workflow to catch events. You can use the stringByEvaluatingJavaScriptFromString: function to run them. [block:code] { "codes": [ { "code": "NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@\"currentCartJSON()\"];", "language": "objectivec" } ] } [/block] [block:parameters] { "data": { "h-0": "Function", "h-1": "Description", "0-0": "currentCartJSON()", "1-0": "postMessagesJSON()", "0-1": "Returns the current updated cart in JSON form. On a finalized purchase the result will be empty.\nThe hash format is { siteId: { productMD5: { title, image, price } } }", "1-1": "The checkout interface triggers postMessages alerts. Since it's impossible to push these updates on mobile devices postMessagesJSON() can be polled periodically to retrieve what's being sent." }, "cols": 2, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "Web" } [/block] On the web you can catch events from outside the checkout iframe like below. [block:code] { "codes": [ { "code": "function TTHandleEvents(event) {\n if (event.data['action'] == 'close_pressed') {\n ...\n }\n}\n\nwindow.addEventListener('message', TTHandleEvents, false);", "language": "javascript" } ] } [/block]
Two Tap fires certain postMessage events during the purchase flow. The object is a hash that looks like: { action: Action, various_args }. On Internet Explorer 9 or earlier the object is a JSON encoded string. [block:parameters] { "data": { "h-0": "Action", "h-1": "Returns", "h-2": "Description", "0-0": "cart_contents_changed", "1-0": "cart_finalized", "2-0": "close_pressed", "0-1": "cart_contents, cart_event, cart_id", "0-2": "This event fires anytime a cart is changed or when a purchase has been completed successfully.\ncart_contents looks like { siteId: { productMD5: { title, image, price, url, original_url, required_fields, required_field_values, fields_input } } }\ncart_event can be 'cart_loaded', 'product_removed', 'product_attributes_updated', or 'cart_finalized'.", "1-2": "This event fires anytime a purchase has completed successfully.", "2-2": "This event fires if the user presses the close button (see the show_close_button parameter)." }, "cols": 3, "rows": 3 } [/block] [block:api-header] { "type": "basic", "title": "iOS" } [/block] We provide a couple of helper functions that you can use in your iOS workflow to catch events. You can use the stringByEvaluatingJavaScriptFromString: function to run them. [block:code] { "codes": [ { "code": "NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@\"currentCartJSON()\"];", "language": "objectivec" } ] } [/block] [block:parameters] { "data": { "h-0": "Function", "h-1": "Description", "0-0": "currentCartJSON()", "1-0": "postMessagesJSON()", "0-1": "Returns the current updated cart in JSON form. On a finalized purchase the result will be empty.\nThe hash format is { siteId: { productMD5: { title, image, price } } }", "1-1": "The checkout interface triggers postMessages alerts. Since it's impossible to push these updates on mobile devices postMessagesJSON() can be polled periodically to retrieve what's being sent." }, "cols": 2, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "Web" } [/block] On the web you can catch events from outside the checkout iframe like below. [block:code] { "codes": [ { "code": "function TTHandleEvents(event) {\n if (event.data['action'] == 'close_pressed') {\n ...\n }\n}\n\nwindow.addEventListener('message', TTHandleEvents, false);", "language": "javascript" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f833","api":{"examples":{"codes":[{"name":"Ruby","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'httparty'\n\npurchase_id = ARGV[0]\n\nfield_type = 'payment'\nexpires_in = 3600\n\nmeta_fields = { \n  'card_type' => 'Visa',\n  'card_name' => 'John Carter',\n  'card_number' => '4111111111111111',\n  'expiry_date_month' => '03',\n  'expiry_date_year' => '2017',\n  'billing_first_name' => 'John',\n  'billing_last_name' => 'Carter',\n  'billing_address' => 'An address',\n  'billing_city' => 'Palo Alto',\n  'billing_state' => 'California',\n  'billing_zip' => '94103',\n  'billing_country' => 'United States of America',\n  'billing_telephone' => '6501231234'\n }\n\n\nresponse = HTTParty.post \"https://api.twotap.com/v1.0/wallet/meta?public_token=PUBLIC_TOKEN\", :body => { \n  'meta_fields' => meta_fields,\n  'field_type' => 'payment',\n  'expires_in' => expires_in \n }\n\nputs response.body","language":"ruby"}]},"results":{"codes":[{"status":200,"language":"json","code":"{\n  \"message\":\"done\",\n  \"meta_id\":\"Tn0SHOSpekKxTcQ3CLbq\"\n}","name":""}]},"settings":"","auth":"required","params":[{"_id":"5650dfe2d984da210073596e","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"5650dfe2d984da210073596d","ref":"","required":true,"desc":"Set it to 'payment'.","default":"","type":"string","name":"field_type","in":"body"},{"_id":"5650dfe2d984da210073596c","ref":"","required":true,"desc":"When this information should expire, in seconds.","default":"","type":"int","name":"expires_in","in":"body"}],"url":"/wallet/meta"},"body":"There are cases where you'd be interested in hiding some data from the consumer.\n\nThe most common use case is when you are interested in prefilling payment data inside the HTML5 interface, but you'd rather keep a [Your Server] <-> Two Tap communication channel for PCI DSS reasons.\n\nMeta allows you to do that.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Using Meta\"\n}\n[/block]\nWhen sending 'input_fields' with the Cart send the meta_id you receive from this endpoint like so: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"input_fields: { \\n  'payment_meta_id': 'meta_id from this endpoint',\\n  'payment_meta_description': 'eg Visa ending in 1111',\\n  'any_other_field': 'field value'\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]","category":"57780374ea758f0e00e6f820","createdAt":"2015-07-10T21:10:42.059Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":15,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"meta","sync_unique":"","title":"/wallet/meta","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/wallet/meta


Body JSON

public_token:
required
string
Your Two Tap public token.
field_type:
required
string
Set it to 'payment'.
expires_in:
required
integer
When this information should expire, in seconds.
There are cases where you'd be interested in hiding some data from the consumer. The most common use case is when you are interested in prefilling payment data inside the HTML5 interface, but you'd rather keep a [Your Server] <-> Two Tap communication channel for PCI DSS reasons. Meta allows you to do that. [block:api-header] { "type": "basic", "title": "Using Meta" } [/block] When sending 'input_fields' with the Cart send the meta_id you receive from this endpoint like so: [block:code] { "codes": [ { "code": "input_fields: { \n 'payment_meta_id': 'meta_id from this endpoint',\n 'payment_meta_description': 'eg Visa ending in 1111',\n 'any_other_field': 'field value'\n}", "language": "json" } ] } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



There are cases where you'd be interested in hiding some data from the consumer. The most common use case is when you are interested in prefilling payment data inside the HTML5 interface, but you'd rather keep a [Your Server] <-> Two Tap communication channel for PCI DSS reasons. Meta allows you to do that. [block:api-header] { "type": "basic", "title": "Using Meta" } [/block] When sending 'input_fields' with the Cart send the meta_id you receive from this endpoint like so: [block:code] { "codes": [ { "code": "input_fields: { \n 'payment_meta_id': 'meta_id from this endpoint',\n 'payment_meta_description': 'eg Visa ending in 1111',\n 'any_other_field': 'field value'\n}", "language": "json" } ] } [/block]
{"category":"57780374ea758f0e00e6f821","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f825","createdAt":"2015-07-09T23:05:16.134Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":16,"body":"You can use the API to create your own personalized checkout experience.\n\nThe interaction is divided into three separate tasks which have to be executed in order: '/cart', '/purchase', '/purchase/confirm'.\n\nIf you want to integrate the Two Tap API directly you should consider using the HTTP integration flow or SMS integration flow. Implementing these flows allows us to intervene in case of issues in the background and resolve them quickly without the shopper noticing anything.\n\nJSONP is enabled for all endpoints. The JSONP callback name is simply 'callback'.","excerpt":"","slug":"api","type":"basic","title":"API Interface","__v":0,"childrenPages":[]}

API Interface


You can use the API to create your own personalized checkout experience. The interaction is divided into three separate tasks which have to be executed in order: '/cart', '/purchase', '/purchase/confirm'. If you want to integrate the Two Tap API directly you should consider using the HTTP integration flow or SMS integration flow. Implementing these flows allows us to intervene in case of issues in the background and resolve them quickly without the shopper noticing anything. JSONP is enabled for all endpoints. The JSONP callback name is simply 'callback'.
You can use the API to create your own personalized checkout experience. The interaction is divided into three separate tasks which have to be executed in order: '/cart', '/purchase', '/purchase/confirm'. If you want to integrate the Two Tap API directly you should consider using the HTTP integration flow or SMS integration flow. Implementing these flows allows us to intervene in case of issues in the background and resolve them quickly without the shopper noticing anything. JSONP is enabled for all endpoints. The JSONP callback name is simply 'callback'.
{"__v":0,"_id":"57780374ea758f0e00e6f826","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"To ask for product information use the [/cart](/docs/cart) endpoint.\n\nAcross the API you will notice a field called cache_time. This controls Two Tap's hard cache of products. \n\nBy default, after Two Tap sees a product it will serve the cached version for 300 seconds (5 minutes). This means if you open the Cart once with a product, close it, and open it again immediately, Two Tap is not going to refresh the information, and will serve the version it stored previously.\n\nFor some apps 5 minutes is too little. With the cache_time variable you can control this interval.\n\nPlease keep in mind that the higher this variable is, the more unreliable Two Tap's product information is. Attributes might go out of stock over the span of 10 minutes, prices might change, and so on.\n\nIt's Two Tap's belief that consumers prefer to have reliable information and are OK with waiting ~5-10sec vs entering all their information and being notified that the attributes they are looking for are, in fact, out of stock.\n\nHowever, with the cache_time variable you can design product pages with a bit older data, and cart pages where you can validate the information properly.","category":"57780374ea758f0e00e6f821","createdAt":"2015-03-15T02:40:44.211Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":17,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"product-availability","sync_unique":"","title":"Real-Time Product Availability","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Real-Time Product Availability


To ask for product information use the [/cart](/docs/cart) endpoint. Across the API you will notice a field called cache_time. This controls Two Tap's hard cache of products. By default, after Two Tap sees a product it will serve the cached version for 300 seconds (5 minutes). This means if you open the Cart once with a product, close it, and open it again immediately, Two Tap is not going to refresh the information, and will serve the version it stored previously. For some apps 5 minutes is too little. With the cache_time variable you can control this interval. Please keep in mind that the higher this variable is, the more unreliable Two Tap's product information is. Attributes might go out of stock over the span of 10 minutes, prices might change, and so on. It's Two Tap's belief that consumers prefer to have reliable information and are OK with waiting ~5-10sec vs entering all their information and being notified that the attributes they are looking for are, in fact, out of stock. However, with the cache_time variable you can design product pages with a bit older data, and cart pages where you can validate the information properly.
To ask for product information use the [/cart](/docs/cart) endpoint. Across the API you will notice a field called cache_time. This controls Two Tap's hard cache of products. By default, after Two Tap sees a product it will serve the cached version for 300 seconds (5 minutes). This means if you open the Cart once with a product, close it, and open it again immediately, Two Tap is not going to refresh the information, and will serve the version it stored previously. For some apps 5 minutes is too little. With the cache_time variable you can control this interval. Please keep in mind that the higher this variable is, the more unreliable Two Tap's product information is. Attributes might go out of stock over the span of 10 minutes, prices might change, and so on. It's Two Tap's belief that consumers prefer to have reliable information and are OK with waiting ~5-10sec vs entering all their information and being notified that the attributes they are looking for are, in fact, out of stock. However, with the cache_time variable you can design product pages with a bit older data, and cart pages where you can validate the information properly.
{"__v":27,"_id":"57780374ea758f0e00e6f827","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"The SMS flow is an easy way to integrate Two Tap. The API will handle the shopper communication via SMS, and all you have to do is confirm the purchase.\n\nThe diagram below describes how you should interact with the API to create an SMS flow.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/VnFdzmpUQUymzaea5pgl_sms_confirm_flow.jpg\",\n        \"sms_confirm_flow.jpg\",\n        \"801\",\n        \"739\",\n        \"#4bb1a7\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\\n\\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\\n\\n**Update** is called after Two Tap sends the order the retailer providing status updates.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Initializing the SMS flow during '/purchase'\"\n}\n[/block]\nTo start the HTTP SMS flow send a confirm option like below with the /purchase request.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"This step is not necessary if you are using the Cart interface.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#!/usr/bin/env ruby\\n\\nfields_input = __INPUT__\\nproducts = __PRODUCTS__\\n\\nconfirm = {}\\nconfirm['method'] = 'sms'\\nconfirm['phone'] = 'the phone number of the shopper'\\nconfirm['sms_confirm_url'] = 'An endpoint on your end where you will handle confirmations.'\\nconfirm['sms_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\\nconfirm['retry_url'] = '(optional) your_url_type://purchase/%%PURCHASE_ID%%/retry'\\n\\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the sms_confirm_url and automatically confirm the purchase. sms_update_url is required in this case.'\\n\\nresponse = RestClient.post \\\"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\\\", { \\n  cart_id: cart_id, \\n  fields_input: fields_input, \\n  products: products,\\n  confirm: confirm \\n}\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"#!/bin/sh\\n\\nPUBLIC_TOKEN=PUBLIC_TOKEN\\nFIELDS_INPUT=FIELDS_INPUT\\nPRODUCTS=PRODUCTS\\n\\ncurl \\\"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\\\" --header \\\"Content-Type: application/json\\\" --data-binary '{\\n  \\\"cart_id\\\": \\\"CART_ID\\\",\\n  \\\"fields_input\\\": \\\"$FIELDS_INPUT\\\",\\n  \\\"products\\\": \\\"$PRODUCTS\\\",\\n  \\\"confirm\\\": {\\n    \\\"method\\\": \\\"sms\\\",\\n    \\\"phone\\\": \\\"the phone number of the shopper\\\",\\n    \\\"sms_confirm_url\\\": \\\"An endpoint on your end where you will handle confirmations.\\\",\\n    \\\"sms_update_url\\\": \\\"An endpoint on your end where we will send the result of the purchase.\\\",\\n    \\\"retry_url\\\": \\\"your_url_type://purchase/PURCHASE_ID/retry\\\"\\n  }\\n}'\\n                  \",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"#!/bin/sh\\n\\nPUBLIC_TOKEN=PUBLIC_TOKEN\\nFIELDS_INPUT=FIELDS_INPUT\\nPRODUCTS=PRODUCTS\\n\\ncurl \\\"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\\\" --header \\\"Content-Type: application/json\\\" --data-binary '{\\n  \\\"cart_id\\\": \\\"CART_ID\\\",\\n  \\\"fields_input\\\": \\\"$FIELDS_INPUT\\\",\\n  \\\"products\\\": \\\"$PRODUCTS\\\",\\n  \\\"confirm\\\": {\\n    \\\"method\\\": \\\"sms\\\",\\n    \\\"phone\\\": \\\"the phone number of the shopper\\\",\\n    \\\"sms_confirm_url\\\": \\\"An endpoint on your end where you will handle confirmations.\\\",\\n    \\\"sms_update_url\\\": \\\"An endpoint on your end where we will send the result of the purchase.\\\",\\n    \\\"retry_url\\\": \\\"your_url_type://purchase/PURCHASE_ID/retry\\\"\\n  }\\n}'\\n                  \",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var request = require(\\\"request\\\");\\nvar public_token = 'PUBLIC_TOKEN';\\nvar fields_input = 'FIELDS_INPUT';\\nvar products = 'PRODUCTS';\\nrequest({\\n  url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\\n  json: { \\n  \\\"cart_id\\\": \\\"CART_ID\\\", \\n  \\\"fields_input\\\": fields_input, \\n  \\\"products\\\": products,\\n  \\\"confirm\\\": {\\n    'method': 'sms',\\n    'phone': 'the phone number of the shopper',\\n    'sms_confirm_url': 'An endpoint on your end where you will handle confirmations.',\\n    'sms_update_url': 'An endpoint on your end where we will send the result of the purchase.',\\n    'retry_url': 'your_url_type://purchase/PURCHASE_ID/retry'\\n  }\\n},\\n  method: \\\"POST\\\"\\n}, function (err, reponse, body) {\\n  console.log(body); \\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"require_once 'Requests/library/Requests.php';\\n\\nRequests::register_autoloader();\\n$public_token = 'PUBLIC_TOKEN';\\n$fields_input = 'FIELDS_INPUT';\\n$products = 'PRODUCTS';\\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\\n$payload = array(\\n  \\\"cart_id\\\" => \\\"CART_ID\\\", \\n  \\\"fields_input\\\" => $fields_input, \\n  \\\"products\\\" => $products,\\n  \\\"confirm\\\" => array(\\n    'method' => 'sms',\\n    'phone' => 'the phone number of the shopper',\\n    'sms_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\\n    'sms_update_url' => 'An endpoint on your end where we will send the result of the purchase.',\\n    'retry_url' => 'your_url_type://purchase/PURCHASE_ID/retry'\\n    )\\n);\\n$response = Requests::post($url, array(), $payload);\\necho $response->body;\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"package main\\n\\nimport (\\n  \\\"fmt\\\"\\n  \\\"net/http\\\"\\n  \\\"io/ioutil\\\"\\n  \\\"bytes\\\"\\n)\\n\\nfunc main() {\\n    public_token := \\\"PUBLIC_TOKEN\\\"\\n    fields_input := \\\"FIELDS_INPUT\\\"\\n    products := \\\"PRODUCTS\\\"\\n    url := \\\"https://api.twotap.com/v1.0/purchase?public_token=\\\" + public_token\\n    var jsonStr = []byte(`{\\n    \\\"cart_id\\\": \\\"CART_ID\\\",\\n    \\\"fields_input\\\": \\\"$FIELDS_INPUT\\\",\\n    \\\"products\\\": \\\"$PRODUCTS\\\",\\n    \\\"confirm\\\": {\\n      \\\"method\\\": \\\"sms\\\",\\n      \\\"phone\\\": \\\"the phone number of the shopper\\\",\\n      \\\"sms_confirm_url\\\": \\\"An endpoint on your end where you will handle confirmations.\\\",\\n      \\\"sms_update_url\\\": \\\"An endpoint on your end where we will send the result of the purchase.\\\",\\n      \\\"retry_url\\\": \\\"your_url_type://purchase/PURCHASE_ID/retry\\\"\\n    }\\n}`)\\n    req, err := http.NewRequest(\\\"POST\\\", url, bytes.NewBuffer(jsonStr))\\n    req.Header.Add(\\\"Content-Type\\\", \\\"application/json\\\")\\n    client := &http.Client{}\\n    resp, err := client.Do(req)\\n    if err != nil {\\n        panic(err)\\n    }\\n    defer resp.Body.Close()\\n    body, _ := ioutil.ReadAll(resp.Body)\\n    fmt.Println(string(body))\\n}\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"using System;\\nusing System.Collections.Generic;\\nusing System.Net.Http;\\nusing System.Net.Http.Headers;\\nusing System.Dynamic;\\nusing System.Text;\\nusing Newtonsoft.Json;\\n\\npublic class EmptyClass\\n{\\n  public static void Main ()\\n  {\\n    using (var client = new HttpClient ()) {\\n      var public_token = \\\"PUBLIC_TOKEN\\\";\\n      var cart_id = \\\"CART_ID\\\";\\n      var fields_input = \\\"FIELDS_INPUT\\\";\\n      var products = \\\"PRODUCTS\\\";\\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\\\"application/json\\\"));\\n      client.BaseAddress = new Uri (\\\"https://api.twotap.com/v1.0/purchase?public_token=\\\" + public_token);\\n      dynamic payload = new ExpandoObject ();\\n      payload.cart_id = cart_id;\\n      payload.fields_input = fields_input;\\n      payload.products = products;\\n      payload.confirm = new ExpandoObject ();\\n      payload.confirm.method = \\\"sms\\\";\\n      payload.confirm.phone = \\\"the phone number of the shopper\\\";\\n      payload.confirm.sms_confirm_url = \\\"An endpoint on your end where you will handle confirmations.\\\";\\n      payload.confirm.sms_update_url = \\\"An endpoint on your end where we will send the result of the purchase.\\\";\\n      payload.confirm.retry_url = \\\"your_url_type://purchase/PURCHASE_ID/retry\\\";\\n      string json = JsonConvert.SerializeObject(payload);\\n      var result = client.PostAsync (\\\"\\\", new StringContent(json, Encoding.UTF8, \\\"application/json\\\")).Result;\\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\\n      Console.WriteLine (resultContent);\\n    }\\n  }\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"SMS confirm URL\"\n}\n[/block]\nBefore Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. \n\nThis is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call.\n\nThis endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products).\n\nPlease keep in mind that, for international orders, this callback might arrive after a day or so.\n\nThe information sent is the same as in the /purchase/status API method.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// example POST API callback:\\n// POST http://an_url/callback\\n//\\n// The information sent is the same as in the /purchase/status API method.\\nexports.confirmURLCallback = function(req, res) {\\n  var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\\n  var testMode = req.body.test_mode;\\n\\n  var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \\n\\n  // Pass whatever testMode is being used to the API call.\\n  if (testMode && testMode.length > 0) {\\n    callPath += \\\"&test_mode=\\\" + testMode;\\n  }\\n\\n  var purchaseId  = req.body.purchase_id;\\n  var uniqueToken = req.body.unique_token;\\n  var sites       = req.body.sites; \\n\\n  // ...Check validity of request...\\n  // Check that you have created the unique token.\\n  // And that the product urls were part of the \\n  // original request.\\n\\n  // Call the Two Tap api to confirm (note https).\\n  rest.post('https://api.twotap.com' + callPath, {\\n    data: { purchase_id: purchaseId },\\n\\n  }).on('complete', function(data, response) {\\n    res.json({});\\n  });  \\n};\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"<?php\\nnamespace AppBundle\\\\Controller;\\n\\nuse Sensio\\\\Bundle\\\\FrameworkExtraBundle\\\\Configuration\\\\Route;\\nuse Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller;\\nuse Symfony\\\\Component\\\\HttpFoundation\\\\Response;\\nuse Symfony\\\\Component\\\\HttpFoundation\\\\Request;\\nuse Symfony\\\\Component\\\\ClassLoader\\\\ClassLoader;\\n\\n$loader = new ClassLoader();\\n$loader->addPrefix('Requests', '/path/to/Requests/library');\\n$loader->register();\\n\\nuse Requests;\\n\\nclass DefaultController extends Controller\\n{\\n    /**\\n     * @Route(\\\"/api/callback\\\")\\n     */\\n    public function indexAction()\\n    {\\n      $request = Request::createFromGlobals();\\n      if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\\n        $data = json_decode($request->getContent(), true);\\n        $request->request->replace(is_array($data) ? $data : array());\\n      }\\n\\n      $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\\n      $testMode = $request->request->get('test_mode');\\n      $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\\n      if (null !== $testMode && strlen($testMode) > 0)\\n        $callPath .= \\\"&test_mode=\\\" . $testMode;\\n      \\n      $purchaseId = $request->request->get('purchase_id');\\n      $uniqueToken = $request->request->get('unique_token');\\n      $sites = $request->request->get('sites');\\n\\n      // ...Check validity of request...\\n      // Check that you have created the unique token.\\n      // And that the product urls were part of the \\n      // original request.\\n\\n      // Call the Two Tap api to confirm (note https).\\n      $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\\n      return new Response($response->body);\\n    }\\n}\\n?>\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"require 'rubygems'\\nrequire 'rest_client'\\n\\nclass SmsController < ApplicationController\\n  def index\\n    private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\\n    test_mode = params[:test_mode]\\n    call_path = '/v1.0/purchase/confirm?private_token=' + private_token\\n\\n    if test_mode && test_mode.size > 0\\n      call_path += '&test_mode=' + test_mode\\n    end\\n\\n    purchase_id = params[:purchase_id]\\n    unique_token = params[:unique_token]\\n    sites = params[:sites]\\n\\n    ## ...Check validity of request...\\n    ## Check that you have created the unique token.\\n    ## And that the product urls were part of the\\n    ## original request.\\n\\n    ## Call the Two Tap api to confirm (note https).\\n    response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\\n\\n    render :nothing => true\\n  end\\nend\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"SMS update url\"\n}\n[/block]\nThis endpoint is called after Two Tap sends the order the retailer providing status updates.\n\nFor domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param.\n\nFor international purchases, this means a change in the purchase.state param.\n\nThe information sent is the same as in the /purchase/status API method.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Two Tap might remove products from international orders\",\n  \"body\": \"Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// example POST API callback:\\n// POST http://an_url/callback\\n//\\n// The information sent is the same as in the /purchase/status API method.\\nexports.updatedURLCallback = function(req, res) {\\n  var purchaseId = req.body.purchase_id;\\n  // ...\\n  res.json({});\\n}\",\n      \"language\": \"javascript\",\n      \"name\": null\n    }\n  ]\n}\n[/block]\nThis endpoint is only called once after Two Tap has finished processing the purchase.\n\nThe information sent is the same as in the /purchase/status API method.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Retrying SMS purchases\"\n}\n[/block]\nUsing the SMS flow if a purchase doesn't go through, which in most cases means payment failure, shoppers receive an SMS with a link to restart the order.\n\nBy default the message looks like this: \"You can restart your purchase anytime: http://ttap.co/XXXXXX\". This opens in Safari, keeping all your branding and options, allowing the shopper to re-enter the information.\n\nOften times on iOS you don't want to open the links in Safari, and you want to redirect to your app. Tweaking the 'retry_url' allows you to do this.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"retry_url: 'your_url_type://purchase/%%PURCHASE_ID%%/retry'\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nWhen they get back to your app in the 'retry' flow you are receiving a purchase_id. All you have to do is to open an UIWebView pointing it to https://checkout.twotap.com/retry?purchase_id=%%PURCHASE_ID%%.","category":"57780374ea758f0e00e6f821","createdAt":"2015-07-09T23:19:33.819Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":18,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"sms-checkout-flow","sync_unique":"","title":"SMS Checkout flow","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

SMS Checkout flow


The SMS flow is an easy way to integrate Two Tap. The API will handle the shopper communication via SMS, and all you have to do is confirm the purchase. The diagram below describes how you should interact with the API to create an SMS flow. [block:image] { "images": [ { "image": [ "https://files.readme.io/VnFdzmpUQUymzaea5pgl_sms_confirm_flow.jpg", "sms_confirm_flow.jpg", "801", "739", "#4bb1a7", "" ] } ] } [/block] [block:callout] { "type": "info", "body": "There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\n\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\n\n**Update** is called after Two Tap sends the order the retailer providing status updates." } [/block] [block:api-header] { "type": "basic", "title": "Initializing the SMS flow during '/purchase'" } [/block] To start the HTTP SMS flow send a confirm option like below with the /purchase request. [block:callout] { "type": "warning", "body": "This step is not necessary if you are using the Cart interface." } [/block] [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nfields_input = __INPUT__\nproducts = __PRODUCTS__\n\nconfirm = {}\nconfirm['method'] = 'sms'\nconfirm['phone'] = 'the phone number of the shopper'\nconfirm['sms_confirm_url'] = 'An endpoint on your end where you will handle confirmations.'\nconfirm['sms_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\nconfirm['retry_url'] = '(optional) your_url_type://purchase/%%PURCHASE_ID%%/retry'\n\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the sms_confirm_url and automatically confirm the purchase. sms_update_url is required in this case.'\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\", { \n cart_id: cart_id, \n fields_input: fields_input, \n products: products,\n confirm: confirm \n}", "language": "ruby" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}'\n ", "language": "curl" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}'\n ", "language": "python" }, { "code": "var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar fields_input = 'FIELDS_INPUT';\nvar products = 'PRODUCTS';\nrequest({\n url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n json: { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'sms',\n 'phone': 'the phone number of the shopper',\n 'sms_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'sms_update_url': 'An endpoint on your end where we will send the result of the purchase.',\n 'retry_url': 'your_url_type://purchase/PURCHASE_ID/retry'\n }\n},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "require_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$fields_input = 'FIELDS_INPUT';\n$products = 'PRODUCTS';\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\n$payload = array(\n \"cart_id\" => \"CART_ID\", \n \"fields_input\" => $fields_input, \n \"products\" => $products,\n \"confirm\" => array(\n 'method' => 'sms',\n 'phone' => 'the phone number of the shopper',\n 'sms_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\n 'sms_update_url' => 'An endpoint on your end where we will send the result of the purchase.',\n 'retry_url' => 'your_url_type://purchase/PURCHASE_ID/retry'\n )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n public_token := \"PUBLIC_TOKEN\"\n fields_input := \"FIELDS_INPUT\"\n products := \"PRODUCTS\"\n url := \"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token\n var jsonStr = []byte(`{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n req.Header.Add(\"Content-Type\", \"application/json\")\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n var public_token = \"PUBLIC_TOKEN\";\n var cart_id = \"CART_ID\";\n var fields_input = \"FIELDS_INPUT\";\n var products = \"PRODUCTS\";\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token);\n dynamic payload = new ExpandoObject ();\n payload.cart_id = cart_id;\n payload.fields_input = fields_input;\n payload.products = products;\n payload.confirm = new ExpandoObject ();\n payload.confirm.method = \"sms\";\n payload.confirm.phone = \"the phone number of the shopper\";\n payload.confirm.sms_confirm_url = \"An endpoint on your end where you will handle confirmations.\";\n payload.confirm.sms_update_url = \"An endpoint on your end where we will send the result of the purchase.\";\n payload.confirm.retry_url = \"your_url_type://purchase/PURCHASE_ID/retry\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "SMS confirm URL" } [/block] Before Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. This is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call. This endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products). Please keep in mind that, for international orders, this callback might arrive after a day or so. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "warning", "body": "**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**" } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\nexports.confirmURLCallback = function(req, res) {\n var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n var testMode = req.body.test_mode;\n\n var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \n\n // Pass whatever testMode is being used to the API call.\n if (testMode && testMode.length > 0) {\n callPath += \"&test_mode=\" + testMode;\n }\n\n var purchaseId = req.body.purchase_id;\n var uniqueToken = req.body.unique_token;\n var sites = req.body.sites; \n\n // ...Check validity of request...\n // Check that you have created the unique token.\n // And that the product urls were part of the \n // original request.\n\n // Call the Two Tap api to confirm (note https).\n rest.post('https://api.twotap.com' + callPath, {\n data: { purchase_id: purchaseId },\n\n }).on('complete', function(data, response) {\n res.json({});\n }); \n};", "language": "javascript" }, { "code": "<?php\nnamespace AppBundle\\Controller;\n\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\ClassLoader\\ClassLoader;\n\n$loader = new ClassLoader();\n$loader->addPrefix('Requests', '/path/to/Requests/library');\n$loader->register();\n\nuse Requests;\n\nclass DefaultController extends Controller\n{\n /**\n * @Route(\"/api/callback\")\n */\n public function indexAction()\n {\n $request = Request::createFromGlobals();\n if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\n $data = json_decode($request->getContent(), true);\n $request->request->replace(is_array($data) ? $data : array());\n }\n\n $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n $testMode = $request->request->get('test_mode');\n $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\n if (null !== $testMode && strlen($testMode) > 0)\n $callPath .= \"&test_mode=\" . $testMode;\n \n $purchaseId = $request->request->get('purchase_id');\n $uniqueToken = $request->request->get('unique_token');\n $sites = $request->request->get('sites');\n\n // ...Check validity of request...\n // Check that you have created the unique token.\n // And that the product urls were part of the \n // original request.\n\n // Call the Two Tap api to confirm (note https).\n $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\n return new Response($response->body);\n }\n}\n?>", "language": "php" }, { "code": "require 'rubygems'\nrequire 'rest_client'\n\nclass SmsController < ApplicationController\n def index\n private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n test_mode = params[:test_mode]\n call_path = '/v1.0/purchase/confirm?private_token=' + private_token\n\n if test_mode && test_mode.size > 0\n call_path += '&test_mode=' + test_mode\n end\n\n purchase_id = params[:purchase_id]\n unique_token = params[:unique_token]\n sites = params[:sites]\n\n ## ...Check validity of request...\n ## Check that you have created the unique token.\n ## And that the product urls were part of the\n ## original request.\n\n ## Call the Two Tap api to confirm (note https).\n response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\n\n render :nothing => true\n end\nend", "language": "ruby" } ] } [/block] [block:api-header] { "type": "basic", "title": "SMS update url" } [/block] This endpoint is called after Two Tap sends the order the retailer providing status updates. For domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param. For international purchases, this means a change in the purchase.state param. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "title": "Two Tap might remove products from international orders", "body": "Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase." } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\nexports.updatedURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n // ...\n res.json({});\n}", "language": "javascript", "name": null } ] } [/block] This endpoint is only called once after Two Tap has finished processing the purchase. The information sent is the same as in the /purchase/status API method. [block:api-header] { "type": "basic", "title": "Retrying SMS purchases" } [/block] Using the SMS flow if a purchase doesn't go through, which in most cases means payment failure, shoppers receive an SMS with a link to restart the order. By default the message looks like this: "You can restart your purchase anytime: http://ttap.co/XXXXXX". This opens in Safari, keeping all your branding and options, allowing the shopper to re-enter the information. Often times on iOS you don't want to open the links in Safari, and you want to redirect to your app. Tweaking the 'retry_url' allows you to do this. [block:code] { "codes": [ { "code": "retry_url: 'your_url_type://purchase/%%PURCHASE_ID%%/retry'", "language": "text" } ] } [/block] When they get back to your app in the 'retry' flow you are receiving a purchase_id. All you have to do is to open an UIWebView pointing it to https://checkout.twotap.com/retry?purchase_id=%%PURCHASE_ID%%.
The SMS flow is an easy way to integrate Two Tap. The API will handle the shopper communication via SMS, and all you have to do is confirm the purchase. The diagram below describes how you should interact with the API to create an SMS flow. [block:image] { "images": [ { "image": [ "https://files.readme.io/VnFdzmpUQUymzaea5pgl_sms_confirm_flow.jpg", "sms_confirm_flow.jpg", "801", "739", "#4bb1a7", "" ] } ] } [/block] [block:callout] { "type": "info", "body": "There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\n\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\n\n**Update** is called after Two Tap sends the order the retailer providing status updates." } [/block] [block:api-header] { "type": "basic", "title": "Initializing the SMS flow during '/purchase'" } [/block] To start the HTTP SMS flow send a confirm option like below with the /purchase request. [block:callout] { "type": "warning", "body": "This step is not necessary if you are using the Cart interface." } [/block] [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nfields_input = __INPUT__\nproducts = __PRODUCTS__\n\nconfirm = {}\nconfirm['method'] = 'sms'\nconfirm['phone'] = 'the phone number of the shopper'\nconfirm['sms_confirm_url'] = 'An endpoint on your end where you will handle confirmations.'\nconfirm['sms_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\nconfirm['retry_url'] = '(optional) your_url_type://purchase/%%PURCHASE_ID%%/retry'\n\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the sms_confirm_url and automatically confirm the purchase. sms_update_url is required in this case.'\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\", { \n cart_id: cart_id, \n fields_input: fields_input, \n products: products,\n confirm: confirm \n}", "language": "ruby" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}'\n ", "language": "curl" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}'\n ", "language": "python" }, { "code": "var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar fields_input = 'FIELDS_INPUT';\nvar products = 'PRODUCTS';\nrequest({\n url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n json: { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'sms',\n 'phone': 'the phone number of the shopper',\n 'sms_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'sms_update_url': 'An endpoint on your end where we will send the result of the purchase.',\n 'retry_url': 'your_url_type://purchase/PURCHASE_ID/retry'\n }\n},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "require_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$fields_input = 'FIELDS_INPUT';\n$products = 'PRODUCTS';\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\n$payload = array(\n \"cart_id\" => \"CART_ID\", \n \"fields_input\" => $fields_input, \n \"products\" => $products,\n \"confirm\" => array(\n 'method' => 'sms',\n 'phone' => 'the phone number of the shopper',\n 'sms_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\n 'sms_update_url' => 'An endpoint on your end where we will send the result of the purchase.',\n 'retry_url' => 'your_url_type://purchase/PURCHASE_ID/retry'\n )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n public_token := \"PUBLIC_TOKEN\"\n fields_input := \"FIELDS_INPUT\"\n products := \"PRODUCTS\"\n url := \"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token\n var jsonStr = []byte(`{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"sms\",\n \"phone\": \"the phone number of the shopper\",\n \"sms_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"sms_update_url\": \"An endpoint on your end where we will send the result of the purchase.\",\n \"retry_url\": \"your_url_type://purchase/PURCHASE_ID/retry\"\n }\n}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n req.Header.Add(\"Content-Type\", \"application/json\")\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n var public_token = \"PUBLIC_TOKEN\";\n var cart_id = \"CART_ID\";\n var fields_input = \"FIELDS_INPUT\";\n var products = \"PRODUCTS\";\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token);\n dynamic payload = new ExpandoObject ();\n payload.cart_id = cart_id;\n payload.fields_input = fields_input;\n payload.products = products;\n payload.confirm = new ExpandoObject ();\n payload.confirm.method = \"sms\";\n payload.confirm.phone = \"the phone number of the shopper\";\n payload.confirm.sms_confirm_url = \"An endpoint on your end where you will handle confirmations.\";\n payload.confirm.sms_update_url = \"An endpoint on your end where we will send the result of the purchase.\";\n payload.confirm.retry_url = \"your_url_type://purchase/PURCHASE_ID/retry\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "SMS confirm URL" } [/block] Before Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. This is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call. This endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products). Please keep in mind that, for international orders, this callback might arrive after a day or so. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "warning", "body": "**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**" } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\nexports.confirmURLCallback = function(req, res) {\n var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n var testMode = req.body.test_mode;\n\n var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \n\n // Pass whatever testMode is being used to the API call.\n if (testMode && testMode.length > 0) {\n callPath += \"&test_mode=\" + testMode;\n }\n\n var purchaseId = req.body.purchase_id;\n var uniqueToken = req.body.unique_token;\n var sites = req.body.sites; \n\n // ...Check validity of request...\n // Check that you have created the unique token.\n // And that the product urls were part of the \n // original request.\n\n // Call the Two Tap api to confirm (note https).\n rest.post('https://api.twotap.com' + callPath, {\n data: { purchase_id: purchaseId },\n\n }).on('complete', function(data, response) {\n res.json({});\n }); \n};", "language": "javascript" }, { "code": "<?php\nnamespace AppBundle\\Controller;\n\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\ClassLoader\\ClassLoader;\n\n$loader = new ClassLoader();\n$loader->addPrefix('Requests', '/path/to/Requests/library');\n$loader->register();\n\nuse Requests;\n\nclass DefaultController extends Controller\n{\n /**\n * @Route(\"/api/callback\")\n */\n public function indexAction()\n {\n $request = Request::createFromGlobals();\n if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\n $data = json_decode($request->getContent(), true);\n $request->request->replace(is_array($data) ? $data : array());\n }\n\n $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n $testMode = $request->request->get('test_mode');\n $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\n if (null !== $testMode && strlen($testMode) > 0)\n $callPath .= \"&test_mode=\" . $testMode;\n \n $purchaseId = $request->request->get('purchase_id');\n $uniqueToken = $request->request->get('unique_token');\n $sites = $request->request->get('sites');\n\n // ...Check validity of request...\n // Check that you have created the unique token.\n // And that the product urls were part of the \n // original request.\n\n // Call the Two Tap api to confirm (note https).\n $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\n return new Response($response->body);\n }\n}\n?>", "language": "php" }, { "code": "require 'rubygems'\nrequire 'rest_client'\n\nclass SmsController < ApplicationController\n def index\n private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n test_mode = params[:test_mode]\n call_path = '/v1.0/purchase/confirm?private_token=' + private_token\n\n if test_mode && test_mode.size > 0\n call_path += '&test_mode=' + test_mode\n end\n\n purchase_id = params[:purchase_id]\n unique_token = params[:unique_token]\n sites = params[:sites]\n\n ## ...Check validity of request...\n ## Check that you have created the unique token.\n ## And that the product urls were part of the\n ## original request.\n\n ## Call the Two Tap api to confirm (note https).\n response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\n\n render :nothing => true\n end\nend", "language": "ruby" } ] } [/block] [block:api-header] { "type": "basic", "title": "SMS update url" } [/block] This endpoint is called after Two Tap sends the order the retailer providing status updates. For domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param. For international purchases, this means a change in the purchase.state param. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "title": "Two Tap might remove products from international orders", "body": "Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase." } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\nexports.updatedURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n // ...\n res.json({});\n}", "language": "javascript", "name": null } ] } [/block] This endpoint is only called once after Two Tap has finished processing the purchase. The information sent is the same as in the /purchase/status API method. [block:api-header] { "type": "basic", "title": "Retrying SMS purchases" } [/block] Using the SMS flow if a purchase doesn't go through, which in most cases means payment failure, shoppers receive an SMS with a link to restart the order. By default the message looks like this: "You can restart your purchase anytime: http://ttap.co/XXXXXX". This opens in Safari, keeping all your branding and options, allowing the shopper to re-enter the information. Often times on iOS you don't want to open the links in Safari, and you want to redirect to your app. Tweaking the 'retry_url' allows you to do this. [block:code] { "codes": [ { "code": "retry_url: 'your_url_type://purchase/%%PURCHASE_ID%%/retry'", "language": "text" } ] } [/block] When they get back to your app in the 'retry' flow you are receiving a purchase_id. All you have to do is to open an UIWebView pointing it to https://checkout.twotap.com/retry?purchase_id=%%PURCHASE_ID%%.
{"__v":22,"_id":"57780374ea758f0e00e6f828","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"The HTTP flow allows you more flexibility and control with shopper communication. You can use push notifications or other ways of prompting her to confirm purchases.\n\nThe diagram below describes how you should interact with the API to create an HTTP flow.\n\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"\",\n      \"image\": [\n        \"https://files.readme.io/DUZwRCwgTjeSmxfsMGr9_http_confirm_flow.jpg\",\n        \"http_confirm_flow.jpg\",\n        \"801\",\n        \"720\",\n        \"#4bb3a9\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\\n\\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\\n\\n**Update** is called after Two Tap sends the order the retailer providing status updates.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Initializing the HTTP flow during '/purchase'\"\n}\n[/block]\nTo start the HTTP SMS flow send a confirm option like below with the /purchase request.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"\",\n  \"body\": \"This step is not necessary if you are using the Cart interface.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#!/usr/bin/env ruby\\n\\nfields_input = __INPUT__\\nproducts = __PRODUCTS__\\n\\nconfirm = {}\\nconfirm['method'] = 'http'\\nconfirm['http_confirm_url']  = 'An endpoint on your end where you will handle confirmations.'\\nconfirm['http_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\\n\\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the http_confirm_url and automatically confirm the purchase. http_update_url is required in this case.'\\n\\nresponse = RestClient.post \\\"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\\\", { \\n  cart_id: cart_id, \\n  fields_input: fields_input, \\n  products: products, \\n  confirm: confirm \\n}\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"#!/bin/sh\\n\\nPUBLIC_TOKEN=PUBLIC_TOKEN\\nFIELDS_INPUT=FIELDS_INPUT\\nPRODUCTS=PRODUCTS\\n\\ncurl \\\"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\\\" --header \\\"Content-Type: application/json\\\" --data-binary '{\\n  \\\"cart_id\\\": \\\"CART_ID\\\",\\n  \\\"fields_input\\\": \\\"$FIELDS_INPUT\\\",\\n  \\\"products\\\": \\\"$PRODUCTS\\\",\\n  \\\"confirm\\\": {\\n    \\\"method\\\": \\\"http\\\",\\n    \\\"http_confirm_url\\\": \\\"An endpoint on your end where you will handle confirmations.\\\",\\n    \\\"http_update_url\\\": \\\"An endpoint on your end where we will send the result of the purchase.\\\"\\n  }\\n}'\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"#!/usr/bin/python\\n\\nimport requests\\nimport json\\n\\npublic_token = 'PUBLIC_TOKEN'\\nfields_input = 'FIELDS_INPUT'\\nproducts = 'PRODUCTS'\\n\\npayload = { \\n  \\\"cart_id\\\": \\\"CART_ID\\\", \\n  \\\"fields_input\\\": fields_input, \\n  \\\"products\\\": products,\\n  \\\"confirm\\\": {\\n    'method': 'http',\\n    'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\\n    'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\\n  }\\n}\\nr = requests.post('https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\\n\\nprint(r.json())\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var request = require(\\\"request\\\");\\nvar public_token = 'PUBLIC_TOKEN';\\nvar fields_input = 'FIELDS_INPUT';\\nvar products = 'PRODUCTS';\\nrequest({\\n  url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\\n  json: { \\n  \\\"cart_id\\\": \\\"CART_ID\\\", \\n  \\\"fields_input\\\": fields_input, \\n  \\\"products\\\": products,\\n  \\\"confirm\\\": {\\n    'method': 'http',\\n    'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\\n    'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\\n  }\\n},\\n  method: \\\"POST\\\"\\n}, function (err, reponse, body) {\\n  console.log(body); \\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"<?php\\nrequire_once 'Requests/library/Requests.php';\\n\\nRequests::register_autoloader();\\n$public_token = 'PUBLIC_TOKEN';\\n$fields_input = 'FIELDS_INPUT';\\n$products = 'PRODUCTS';\\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\\n$payload = array(\\n  \\\"cart_id\\\" => \\\"CART_ID\\\", \\n  \\\"fields_input\\\" => $fields_input, \\n  \\\"products\\\" => $products,\\n  \\\"confirm\\\" => array(\\n    'method' => 'http',\\n    'http_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\\n    'http_update_url' => 'An endpoint on your end where we will send the result of the purchase.'\\n    )\\n);\\n$response = Requests::post($url, array(), $payload);\\necho $response->body;\\n?>\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"package main\\n\\nimport (\\n  \\\"fmt\\\"\\n  \\\"net/http\\\"\\n  \\\"io/ioutil\\\"\\n  \\\"bytes\\\"\\n)\\n\\nfunc main() {\\n    public_token := \\\"PUBLIC_TOKEN\\\"\\n    fields_input := \\\"FIELDS_INPUT\\\"\\n    products := \\\"PRODUCTS\\\"\\n    url := \\\"https://api.twotap.com/v1.0/purchase?public_token=\\\" + public_token\\n    var jsonStr = []byte(`{\\n    \\\"cart_id\\\": \\\"CART_ID\\\",\\n    \\\"fields_input\\\": \\\"$FIELDS_INPUT\\\",\\n    \\\"products\\\": \\\"$PRODUCTS\\\",\\n    \\\"confirm\\\": {\\n      \\\"method\\\": \\\"http\\\",\\n      \\\"http_confirm_url\\\": \\\"An endpoint on your end where you will handle confirmations.\\\",\\n      \\\"http_update_url\\\": \\\"An endpoint on your end where we will send the result of the purchase.\\\"\\n    }\\n}`)\\n    req, err := http.NewRequest(\\\"POST\\\", url, bytes.NewBuffer(jsonStr))\\n    req.Header.Add(\\\"Content-Type\\\", \\\"application/json\\\")\\n    client := &http.Client{}\\n    resp, err := client.Do(req)\\n    if err != nil {\\n        panic(err)\\n    }\\n    defer resp.Body.Close()\\n    body, _ := ioutil.ReadAll(resp.Body)\\n    fmt.Println(string(body))\\n}\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"using System;\\nusing System.Collections.Generic;\\nusing System.Net.Http;\\nusing System.Net.Http.Headers;\\nusing System.Dynamic;\\nusing System.Text;\\nusing Newtonsoft.Json;\\n\\npublic class EmptyClass\\n{\\n  public static void Main ()\\n  {\\n    using (var client = new HttpClient ()) {\\n      var public_token = \\\"PUBLIC_TOKEN\\\";\\n      var cart_id = \\\"CART_ID\\\";\\n      var fields_input = \\\"FIELDS_INPUT\\\";\\n      var products = \\\"PRODUCTS\\\";\\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\\\"application/json\\\"));\\n      client.BaseAddress = new Uri (\\\"https://api.twotap.com/v1.0/purchase?public_token=\\\" + public_token);\\n      dynamic payload = new ExpandoObject ();\\n      payload.cart_id = cart_id;\\n      payload.fields_input = fields_input;\\n      payload.products = products;\\n      payload.confirm = new ExpandoObject ();\\n      payload.confirm.method = \\\"http\\\";\\n      payload.confirm.http_confirm_url = \\\"An endpoint on your end where you will handle confirmations.\\\";\\n      payload.confirm.http_update_url = \\\"An endpoint on your end where we will send the result of the purchase.\\\";\\n      string json = JsonConvert.SerializeObject(payload);\\n      var result = client.PostAsync (\\\"\\\", new StringContent(json, Encoding.UTF8, \\\"application/json\\\")).Result;\\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\\n      Console.WriteLine (resultContent);\\n    }\\n  }\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"HTTP confirm URL (confirm callback)\"\n}\n[/block]\nBefore Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. \n\nThis is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call.\n\nThis endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products).\n\nPlease keep in mind that, for international orders, this callback might arrive after a day or so.\n\nThe information sent is the same as in the /purchase/status API method.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"If our estimates were lower than the final purchase prices or if there were coupons/gift cards with the order confirm_with_user will be true and you should **confirm the new prices with the shopper**. The confirmation message is in the confirm_message variable.\\n\\nWe take care of this automatically in the SMS flow.\",\n  \"title\": \"Wrong estimations for domestic orders\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"\",\n  \"body\": \"Please note that 5 minutes after this call the session will expire.\\n\\n**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\n// example POST API callback:\\n// POST http://an_url/callback\\n//\\n// The information sent is the same as in the /purchase/status API method.\\n// Two extra arguments:\\n// confirm_with_user - true or false\\n// confirm_message - A string representing a message to ask the user \\nexports.confirmURLCallback = function(req, res) {\\n  var purchaseId      = req.body.purchase_id;\\n  var sites           = req.body.sites;\\n  var confirmWithUser = req.body.confirm_with_user;\\n  var confirmMessage  = req.body.confirm_message;\\n\\n  if (confirmWithUser) {\\n    // Confirm with shopper, use confirmMessage.\\n  } else {\\n    confirm();\\n  }  \\n\\n  res.json({});\\n}\\n\\n// Call this when you are ready to confirm the purchase:\\nfunction confirm() {\\n  var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\\n  var testMode = req.body.test_mode;\\n\\n  var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \\n  // Pass whatever testMode is being used to the API call.\\n  if (testMode && testMode.length > 0) {\\n    callPath += \\\"&test_mode=\\\" + testMode;\\n  }\\n\\n  // Call the Two Tap api to confirm (note https).\\n  rest.post('https://api.twotap.com' + callPath, {\\n    data: { purchase_id: purchaseId },\\n  }).on('complete', function(data, response) {\\n  });\\n\\n  res.json({});\\n}\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"<?\\nnamespace AppBundle\\\\Controller;\\n\\nuse Sensio\\\\Bundle\\\\FrameworkExtraBundle\\\\Configuration\\\\Route;\\nuse Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller;\\nuse Symfony\\\\Component\\\\HttpFoundation\\\\Response;\\nuse Symfony\\\\Component\\\\HttpFoundation\\\\Request;\\nuse Symfony\\\\Component\\\\ClassLoader\\\\ClassLoader;\\n\\n$loader = new ClassLoader();\\n$loader->addPrefix('Requests', '/path/to/Requests/library');\\n$loader->register();\\n\\nuse Requests;\\n\\nclass DefaultController extends Controller\\n{\\n    /**\\n     * @Route(\\\"/api/callback\\\")\\n     */\\n    public function indexAction()\\n    {\\n      $request = Request::createFromGlobals();\\n      if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\\n        $data = json_decode($request->getContent(), true);\\n        $request->request->replace(is_array($data) ? $data : array());\\n      }\\n\\n      $purchaseId = $request->request->get('purchase_id');\\n      $sites = $request->request->get('sites');\\n      $confirmWithUser = $request->request->get('confirm_with_user');\\n      $confirmMessage = $request->request->get('confirm_message');\\n\\n      if (null !== $confirmMessage) {\\n        // Confirm with shopper, use confirmMessage.\\n      }\\n      else {\\n        $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\\n        $testMode = $request->request->get('test_mode');\\n\\n        $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\\n        // Pass whatever testMode is being used to the API call.\\n        if (null !== $testMode && strlen($testMode) > 0)\\n          $callPath .= \\\"&test_mode=\\\" . $testMode;\\n\\n        // Call the Two Tap api to confirm (note https).\\n        $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\\n        return new Response('{}');\\n      }\\n      return new Response('{}');\\n    }\\n}\\n?>\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"require 'rubygems'\\nrequire 'rest_client'\\n\\nclass HttpController < ApplicationController\\n  def index\\n    purchase_id = params[:purchase_id]\\n    sites = params[:sites]\\n    confirm_with_user = params[:confirm_with_user]\\n    confirm_message = params[:confirm_message]\\n\\n    if confirm_with_user \\n      ## Confirm with shopper, use confirm_message.\\n      render :nothing => true\\n\\n    else\\n      private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\\n      test_mode = params[:test_mode]\\n      call_path = '/v1.0/purchase/confirm?private_token=' + private_token\\n\\n      if test_mode && test_mode.size > 0\\n        callPath += \\\"&test_mode=\\\" + test_mode\\n      end\\n\\n      response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\\n      render :json => response.body\\n    end\\n  end\\nend               \",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"from django.http import HttpResponse\\nfrom django.views.decorators.csrf import csrf_exempt\\nimport json, pprint, requests\\n\\n@csrf_exempt\\ndef index(request):\\n  json_data = json.loads(request.body);\\n\\n  purchaseId = json_data['purchase_id']\\n  sites = json_data['sites']\\n  confirmWithUser = json_data['confirm_with_user']\\n  confirmMessage = json_data['confirm_message']\\n\\n  if confirmWithUser:\\n    # Confirm with shopper, use confirmMessage.\\n  else:\\n    privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN'\\n    testMode = json_data['test_mode']\\n\\n    callPath = '/v1.0/purchase/confirm?private_token=' + privateToken\\n    # Pass whatever testMode is being used to the API call.\\n    if 'test_mode' in json_data:\\n      callPath += '&test_mode=' + json_data['test_mode']\\n\\n    # Call the Two Tap api to confirm (note https).\\n    payload = {'purchase_id': purchaseId}\\n    response = requests.post('https://api.twotap.com' + callPath,\\n      data=json.dumps(payload), headers={'Content-Type': 'application/json'})\\n    return HttpResponse(response.text, content_type='application/json')\\n  return HttpResponse('{}')\",\n      \"language\": \"python\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"HTTP update URL\"\n}\n[/block]\nThis endpoint is called after Two Tap sends the order the retailer providing status updates.\n\nFor domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param.\n\nFor international purchases, this means a change in the purchase.state param.\n\nThe information sent is the same as in the /purchase/status API method.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Two Tap might remove products from international orders\",\n  \"body\": \"Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// example POST API callback:\\n// POST http://an_url/callback\\n//\\n// The information sent is the same as in the /purchase/status API method.\\n// One extra argument:\\n// final_message - A string representing a confirmation message to the user\\nexports.updatedURLCallback = function(req, res) {\\n  var purchaseId = req.body.purchase_id;\\n  // ...\\n  res.json({});\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis endpoint is only called once after Two Tap has finished processing the purchase.\n\nThe information sent is the same as in the /purchase/status API method.","category":"57780374ea758f0e00e6f821","createdAt":"2015-07-09T23:33:55.315Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":19,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"http-checkout-flow","sync_unique":"","title":"HTTP Checkout flow","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

HTTP Checkout flow


The HTTP flow allows you more flexibility and control with shopper communication. You can use push notifications or other ways of prompting her to confirm purchases. The diagram below describes how you should interact with the API to create an HTTP flow. [block:image] { "images": [ { "caption": "", "image": [ "https://files.readme.io/DUZwRCwgTjeSmxfsMGr9_http_confirm_flow.jpg", "http_confirm_flow.jpg", "801", "720", "#4bb3a9", "" ] } ] } [/block] [block:callout] { "type": "info", "body": "There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\n\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\n\n**Update** is called after Two Tap sends the order the retailer providing status updates." } [/block] [block:api-header] { "type": "basic", "title": "Initializing the HTTP flow during '/purchase'" } [/block] To start the HTTP SMS flow send a confirm option like below with the /purchase request. [block:callout] { "type": "warning", "title": "", "body": "This step is not necessary if you are using the Cart interface." } [/block] [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nfields_input = __INPUT__\nproducts = __PRODUCTS__\n\nconfirm = {}\nconfirm['method'] = 'http'\nconfirm['http_confirm_url'] = 'An endpoint on your end where you will handle confirmations.'\nconfirm['http_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\n\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the http_confirm_url and automatically confirm the purchase. http_update_url is required in this case.'\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\", { \n cart_id: cart_id, \n fields_input: fields_input, \n products: products, \n confirm: confirm \n}", "language": "ruby" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"http\",\n \"http_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"http_update_url\": \"An endpoint on your end where we will send the result of the purchase.\"\n }\n}'", "language": "curl" }, { "code": "#!/usr/bin/python\n\nimport requests\nimport json\n\npublic_token = 'PUBLIC_TOKEN'\nfields_input = 'FIELDS_INPUT'\nproducts = 'PRODUCTS'\n\npayload = { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'http',\n 'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\n }\n}\nr = requests.post('https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(r.json())", "language": "python" }, { "code": "var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar fields_input = 'FIELDS_INPUT';\nvar products = 'PRODUCTS';\nrequest({\n url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n json: { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'http',\n 'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\n }\n},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$fields_input = 'FIELDS_INPUT';\n$products = 'PRODUCTS';\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\n$payload = array(\n \"cart_id\" => \"CART_ID\", \n \"fields_input\" => $fields_input, \n \"products\" => $products,\n \"confirm\" => array(\n 'method' => 'http',\n 'http_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url' => 'An endpoint on your end where we will send the result of the purchase.'\n )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n public_token := \"PUBLIC_TOKEN\"\n fields_input := \"FIELDS_INPUT\"\n products := \"PRODUCTS\"\n url := \"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token\n var jsonStr = []byte(`{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"http\",\n \"http_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"http_update_url\": \"An endpoint on your end where we will send the result of the purchase.\"\n }\n}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n req.Header.Add(\"Content-Type\", \"application/json\")\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n var public_token = \"PUBLIC_TOKEN\";\n var cart_id = \"CART_ID\";\n var fields_input = \"FIELDS_INPUT\";\n var products = \"PRODUCTS\";\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token);\n dynamic payload = new ExpandoObject ();\n payload.cart_id = cart_id;\n payload.fields_input = fields_input;\n payload.products = products;\n payload.confirm = new ExpandoObject ();\n payload.confirm.method = \"http\";\n payload.confirm.http_confirm_url = \"An endpoint on your end where you will handle confirmations.\";\n payload.confirm.http_update_url = \"An endpoint on your end where we will send the result of the purchase.\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "HTTP confirm URL (confirm callback)" } [/block] Before Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. This is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call. This endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products). Please keep in mind that, for international orders, this callback might arrive after a day or so. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "body": "If our estimates were lower than the final purchase prices or if there were coupons/gift cards with the order confirm_with_user will be true and you should **confirm the new prices with the shopper**. The confirmation message is in the confirm_message variable.\n\nWe take care of this automatically in the SMS flow.", "title": "Wrong estimations for domestic orders" } [/block] [block:callout] { "type": "warning", "title": "", "body": "Please note that 5 minutes after this call the session will expire.\n\n**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**" } [/block] [block:code] { "codes": [ { "code": "\n// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\n// Two extra arguments:\n// confirm_with_user - true or false\n// confirm_message - A string representing a message to ask the user \nexports.confirmURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n var sites = req.body.sites;\n var confirmWithUser = req.body.confirm_with_user;\n var confirmMessage = req.body.confirm_message;\n\n if (confirmWithUser) {\n // Confirm with shopper, use confirmMessage.\n } else {\n confirm();\n } \n\n res.json({});\n}\n\n// Call this when you are ready to confirm the purchase:\nfunction confirm() {\n var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n var testMode = req.body.test_mode;\n\n var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \n // Pass whatever testMode is being used to the API call.\n if (testMode && testMode.length > 0) {\n callPath += \"&test_mode=\" + testMode;\n }\n\n // Call the Two Tap api to confirm (note https).\n rest.post('https://api.twotap.com' + callPath, {\n data: { purchase_id: purchaseId },\n }).on('complete', function(data, response) {\n });\n\n res.json({});\n}", "language": "javascript" }, { "code": "<?\nnamespace AppBundle\\Controller;\n\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\ClassLoader\\ClassLoader;\n\n$loader = new ClassLoader();\n$loader->addPrefix('Requests', '/path/to/Requests/library');\n$loader->register();\n\nuse Requests;\n\nclass DefaultController extends Controller\n{\n /**\n * @Route(\"/api/callback\")\n */\n public function indexAction()\n {\n $request = Request::createFromGlobals();\n if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\n $data = json_decode($request->getContent(), true);\n $request->request->replace(is_array($data) ? $data : array());\n }\n\n $purchaseId = $request->request->get('purchase_id');\n $sites = $request->request->get('sites');\n $confirmWithUser = $request->request->get('confirm_with_user');\n $confirmMessage = $request->request->get('confirm_message');\n\n if (null !== $confirmMessage) {\n // Confirm with shopper, use confirmMessage.\n }\n else {\n $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n $testMode = $request->request->get('test_mode');\n\n $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\n // Pass whatever testMode is being used to the API call.\n if (null !== $testMode && strlen($testMode) > 0)\n $callPath .= \"&test_mode=\" . $testMode;\n\n // Call the Two Tap api to confirm (note https).\n $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\n return new Response('{}');\n }\n return new Response('{}');\n }\n}\n?>", "language": "php" }, { "code": "require 'rubygems'\nrequire 'rest_client'\n\nclass HttpController < ApplicationController\n def index\n purchase_id = params[:purchase_id]\n sites = params[:sites]\n confirm_with_user = params[:confirm_with_user]\n confirm_message = params[:confirm_message]\n\n if confirm_with_user \n ## Confirm with shopper, use confirm_message.\n render :nothing => true\n\n else\n private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n test_mode = params[:test_mode]\n call_path = '/v1.0/purchase/confirm?private_token=' + private_token\n\n if test_mode && test_mode.size > 0\n callPath += \"&test_mode=\" + test_mode\n end\n\n response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\n render :json => response.body\n end\n end\nend ", "language": "ruby" }, { "code": "from django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nimport json, pprint, requests\n\n@csrf_exempt\ndef index(request):\n json_data = json.loads(request.body);\n\n purchaseId = json_data['purchase_id']\n sites = json_data['sites']\n confirmWithUser = json_data['confirm_with_user']\n confirmMessage = json_data['confirm_message']\n\n if confirmWithUser:\n # Confirm with shopper, use confirmMessage.\n else:\n privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n testMode = json_data['test_mode']\n\n callPath = '/v1.0/purchase/confirm?private_token=' + privateToken\n # Pass whatever testMode is being used to the API call.\n if 'test_mode' in json_data:\n callPath += '&test_mode=' + json_data['test_mode']\n\n # Call the Two Tap api to confirm (note https).\n payload = {'purchase_id': purchaseId}\n response = requests.post('https://api.twotap.com' + callPath,\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n return HttpResponse(response.text, content_type='application/json')\n return HttpResponse('{}')", "language": "python" } ] } [/block] [block:api-header] { "type": "basic", "title": "HTTP update URL" } [/block] This endpoint is called after Two Tap sends the order the retailer providing status updates. For domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param. For international purchases, this means a change in the purchase.state param. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "title": "Two Tap might remove products from international orders", "body": "Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase." } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\n// One extra argument:\n// final_message - A string representing a confirmation message to the user\nexports.updatedURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n // ...\n res.json({});\n}", "language": "javascript" } ] } [/block] This endpoint is only called once after Two Tap has finished processing the purchase. The information sent is the same as in the /purchase/status API method.
The HTTP flow allows you more flexibility and control with shopper communication. You can use push notifications or other ways of prompting her to confirm purchases. The diagram below describes how you should interact with the API to create an HTTP flow. [block:image] { "images": [ { "caption": "", "image": [ "https://files.readme.io/DUZwRCwgTjeSmxfsMGr9_http_confirm_flow.jpg", "http_confirm_flow.jpg", "801", "720", "#4bb3a9", "" ] } ] } [/block] [block:callout] { "type": "info", "body": "There are two callbacks (webhooks) in the API flow: confirm and update. You must implement these in your backend, server-side.\n\n**Confirm** is designed as a safety mechanism in case you want to cancel the order at the last moment. Because /purchase/confirm requires a private token which should be kept hidden on your end, we can ensure that the purchase is really coming from you.\n\n**Update** is called after Two Tap sends the order the retailer providing status updates." } [/block] [block:api-header] { "type": "basic", "title": "Initializing the HTTP flow during '/purchase'" } [/block] To start the HTTP SMS flow send a confirm option like below with the /purchase request. [block:callout] { "type": "warning", "title": "", "body": "This step is not necessary if you are using the Cart interface." } [/block] [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nfields_input = __INPUT__\nproducts = __PRODUCTS__\n\nconfirm = {}\nconfirm['method'] = 'http'\nconfirm['http_confirm_url'] = 'An endpoint on your end where you will handle confirmations.'\nconfirm['http_update_url'] = '(optional) An endpoint on your end that gets called when a purchase changes state.'\n\nconfirm['skip_confirm'] = '(optional and dangerous) Enter your private token here to skip the http_confirm_url and automatically confirm the purchase. http_update_url is required in this case.'\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\", { \n cart_id: cart_id, \n fields_input: fields_input, \n products: products, \n confirm: confirm \n}", "language": "ruby" }, { "code": "#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nFIELDS_INPUT=FIELDS_INPUT\nPRODUCTS=PRODUCTS\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"http\",\n \"http_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"http_update_url\": \"An endpoint on your end where we will send the result of the purchase.\"\n }\n}'", "language": "curl" }, { "code": "#!/usr/bin/python\n\nimport requests\nimport json\n\npublic_token = 'PUBLIC_TOKEN'\nfields_input = 'FIELDS_INPUT'\nproducts = 'PRODUCTS'\n\npayload = { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'http',\n 'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\n }\n}\nr = requests.post('https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(r.json())", "language": "python" }, { "code": "var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar fields_input = 'FIELDS_INPUT';\nvar products = 'PRODUCTS';\nrequest({\n url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n json: { \n \"cart_id\": \"CART_ID\", \n \"fields_input\": fields_input, \n \"products\": products,\n \"confirm\": {\n 'method': 'http',\n 'http_confirm_url': 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url': 'An endpoint on your end where we will send the result of the purchase.'\n }\n},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$fields_input = 'FIELDS_INPUT';\n$products = 'PRODUCTS';\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\n$payload = array(\n \"cart_id\" => \"CART_ID\", \n \"fields_input\" => $fields_input, \n \"products\" => $products,\n \"confirm\" => array(\n 'method' => 'http',\n 'http_confirm_url' => 'An endpoint on your end where you will handle confirmations.',\n 'http_update_url' => 'An endpoint on your end where we will send the result of the purchase.'\n )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n public_token := \"PUBLIC_TOKEN\"\n fields_input := \"FIELDS_INPUT\"\n products := \"PRODUCTS\"\n url := \"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token\n var jsonStr = []byte(`{\n \"cart_id\": \"CART_ID\",\n \"fields_input\": \"$FIELDS_INPUT\",\n \"products\": \"$PRODUCTS\",\n \"confirm\": {\n \"method\": \"http\",\n \"http_confirm_url\": \"An endpoint on your end where you will handle confirmations.\",\n \"http_update_url\": \"An endpoint on your end where we will send the result of the purchase.\"\n }\n}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n req.Header.Add(\"Content-Type\", \"application/json\")\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n var public_token = \"PUBLIC_TOKEN\";\n var cart_id = \"CART_ID\";\n var fields_input = \"FIELDS_INPUT\";\n var products = \"PRODUCTS\";\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token);\n dynamic payload = new ExpandoObject ();\n payload.cart_id = cart_id;\n payload.fields_input = fields_input;\n payload.products = products;\n payload.confirm = new ExpandoObject ();\n payload.confirm.method = \"http\";\n payload.confirm.http_confirm_url = \"An endpoint on your end where you will handle confirmations.\";\n payload.confirm.http_update_url = \"An endpoint on your end where we will send the result of the purchase.\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "HTTP confirm URL (confirm callback)" } [/block] Before Two Tap finalizes the purchase on the retailer sites it asks you to confirm it. This is done for security reasons and also in case our estimator was wrong for domestic purchases. Check that the unique_token and the list of products match the ones from your initial call. This endpoint might not be called if the purchase is refused early on (for instance, in case of out of stock products). Please keep in mind that, for international orders, this callback might arrive after a day or so. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "body": "If our estimates were lower than the final purchase prices or if there were coupons/gift cards with the order confirm_with_user will be true and you should **confirm the new prices with the shopper**. The confirmation message is in the confirm_message variable.\n\nWe take care of this automatically in the SMS flow.", "title": "Wrong estimations for domestic orders" } [/block] [block:callout] { "type": "warning", "title": "", "body": "Please note that 5 minutes after this call the session will expire.\n\n**Always hit /purchase/confirm, even if the callback message is 'has_failures'. For example, on a four-store purchase, if only one store had issues (like an out of stock product), the purchase can still be confirmed on the other three.**" } [/block] [block:code] { "codes": [ { "code": "\n// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\n// Two extra arguments:\n// confirm_with_user - true or false\n// confirm_message - A string representing a message to ask the user \nexports.confirmURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n var sites = req.body.sites;\n var confirmWithUser = req.body.confirm_with_user;\n var confirmMessage = req.body.confirm_message;\n\n if (confirmWithUser) {\n // Confirm with shopper, use confirmMessage.\n } else {\n confirm();\n } \n\n res.json({});\n}\n\n// Call this when you are ready to confirm the purchase:\nfunction confirm() {\n var privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n var testMode = req.body.test_mode;\n\n var callPath = '/v1.0/purchase/confirm?private_token=' + privateToken; \n // Pass whatever testMode is being used to the API call.\n if (testMode && testMode.length > 0) {\n callPath += \"&test_mode=\" + testMode;\n }\n\n // Call the Two Tap api to confirm (note https).\n rest.post('https://api.twotap.com' + callPath, {\n data: { purchase_id: purchaseId },\n }).on('complete', function(data, response) {\n });\n\n res.json({});\n}", "language": "javascript" }, { "code": "<?\nnamespace AppBundle\\Controller;\n\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\ClassLoader\\ClassLoader;\n\n$loader = new ClassLoader();\n$loader->addPrefix('Requests', '/path/to/Requests/library');\n$loader->register();\n\nuse Requests;\n\nclass DefaultController extends Controller\n{\n /**\n * @Route(\"/api/callback\")\n */\n public function indexAction()\n {\n $request = Request::createFromGlobals();\n if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {\n $data = json_decode($request->getContent(), true);\n $request->request->replace(is_array($data) ? $data : array());\n }\n\n $purchaseId = $request->request->get('purchase_id');\n $sites = $request->request->get('sites');\n $confirmWithUser = $request->request->get('confirm_with_user');\n $confirmMessage = $request->request->get('confirm_message');\n\n if (null !== $confirmMessage) {\n // Confirm with shopper, use confirmMessage.\n }\n else {\n $privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN';\n $testMode = $request->request->get('test_mode');\n\n $callPath = '/v1.0/purchase/confirm?private_token=' . $privateToken;\n // Pass whatever testMode is being used to the API call.\n if (null !== $testMode && strlen($testMode) > 0)\n $callPath .= \"&test_mode=\" . $testMode;\n\n // Call the Two Tap api to confirm (note https).\n $response = Requests::post('https://api.twotap.com' . $callPath, array(), array('purchase_id' => $purchaseId));\n return new Response('{}');\n }\n return new Response('{}');\n }\n}\n?>", "language": "php" }, { "code": "require 'rubygems'\nrequire 'rest_client'\n\nclass HttpController < ApplicationController\n def index\n purchase_id = params[:purchase_id]\n sites = params[:sites]\n confirm_with_user = params[:confirm_with_user]\n confirm_message = params[:confirm_message]\n\n if confirm_with_user \n ## Confirm with shopper, use confirm_message.\n render :nothing => true\n\n else\n private_token = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n test_mode = params[:test_mode]\n call_path = '/v1.0/purchase/confirm?private_token=' + private_token\n\n if test_mode && test_mode.size > 0\n callPath += \"&test_mode=\" + test_mode\n end\n\n response = RestClient.post 'https://api.twotap.com' + call_path, { purchase_id: purchase_id }\n render :json => response.body\n end\n end\nend ", "language": "ruby" }, { "code": "from django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nimport json, pprint, requests\n\n@csrf_exempt\ndef index(request):\n json_data = json.loads(request.body);\n\n purchaseId = json_data['purchase_id']\n sites = json_data['sites']\n confirmWithUser = json_data['confirm_with_user']\n confirmMessage = json_data['confirm_message']\n\n if confirmWithUser:\n # Confirm with shopper, use confirmMessage.\n else:\n privateToken = 'YOUR_PRIVATE_TWOTAP_TOKEN'\n testMode = json_data['test_mode']\n\n callPath = '/v1.0/purchase/confirm?private_token=' + privateToken\n # Pass whatever testMode is being used to the API call.\n if 'test_mode' in json_data:\n callPath += '&test_mode=' + json_data['test_mode']\n\n # Call the Two Tap api to confirm (note https).\n payload = {'purchase_id': purchaseId}\n response = requests.post('https://api.twotap.com' + callPath,\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n return HttpResponse(response.text, content_type='application/json')\n return HttpResponse('{}')", "language": "python" } ] } [/block] [block:api-header] { "type": "basic", "title": "HTTP update URL" } [/block] This endpoint is called after Two Tap sends the order the retailer providing status updates. For domestic purchases, this means after injection or when a change happens in the purchase.sites[site_id].remote_state param. For international purchases, this means a change in the purchase.state param. The information sent is the same as in the /purchase/status API method. [block:callout] { "type": "danger", "title": "Two Tap might remove products from international orders", "body": "Being the merchant of record, Two Tap might contact the consumer if one or more products are not deliverable and remove them from the purchase." } [/block] [block:code] { "codes": [ { "code": "// example POST API callback:\n// POST http://an_url/callback\n//\n// The information sent is the same as in the /purchase/status API method.\n// One extra argument:\n// final_message - A string representing a confirmation message to the user\nexports.updatedURLCallback = function(req, res) {\n var purchaseId = req.body.purchase_id;\n // ...\n res.json({});\n}", "language": "javascript" } ] } [/block] This endpoint is only called once after Two Tap has finished processing the purchase. The information sent is the same as in the /purchase/status API method.
{"__v":3,"_id":"57780374ea758f0e00e6f829","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token.\n\nCallbacks are also a convenient way of storing important information about the purchase on your end.\n\nDepending on what confirm mode you are using (the default mode is SMS), see the SMS API or HTTP API confirm flows, with example code on how to implement the callbacks.\n\nWe provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"bash  <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK\",\n      \"language\": \"text\",\n      \"name\": null\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"\",\n  \"body\": \"Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders.\"\n}\n[/block]\nOnce everything is set up try placing an order with test_mode=fake_confirm.\n\nIn 'fake_confirm' test mode the API will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"\",\n  \"body\": \"It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors.\"\n}\n[/block]\nIf you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/).\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"International ToS Approval Box\"\n}\n[/block]\nIn the case of international orders, for legal compliance reasons, it's mandatory that all apps display a warning during checkout that the order is being fulfilled by Two Tap.\n\nBelow you can find some mockups. You can find the different Two Tap logos in SVG format here: [standard](https://core.twotap.com/logos/twotap_logo.svg), [light](https://core.twotap.com/logos/twotap_logo_light.svg), [dark](https://core.twotap.com/logos/twotap_logo_dark.svg). The ToS link is https://twotap.com/terms-intl, and the Privacy link is https://twotap.com/privacy.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/YnTaRdMYTYStviBBZcu8_mb-tt-tos-variations.png\",\n        \"mb-tt-tos-variations.png\",\n        \"1500\",\n        \"2024\",\n        \"#e45362\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]","category":"57780374ea758f0e00e6f821","createdAt":"2015-07-09T23:49:38.980Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":20,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"testing-api","sync_unique":"","title":"Testing","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Testing


The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token. Callbacks are also a convenient way of storing important information about the purchase on your end. Depending on what confirm mode you are using (the default mode is SMS), see the SMS API or HTTP API confirm flows, with example code on how to implement the callbacks. We provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet: [block:code] { "codes": [ { "code": "bash <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK", "language": "text", "name": null } ] } [/block] [block:callout] { "type": "warning", "title": "", "body": "Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders." } [/block] Once everything is set up try placing an order with test_mode=fake_confirm. In 'fake_confirm' test mode the API will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order. [block:callout] { "type": "info", "title": "", "body": "It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors." } [/block] If you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/). [block:api-header] { "type": "basic", "title": "International ToS Approval Box" } [/block] In the case of international orders, for legal compliance reasons, it's mandatory that all apps display a warning during checkout that the order is being fulfilled by Two Tap. Below you can find some mockups. You can find the different Two Tap logos in SVG format here: [standard](https://core.twotap.com/logos/twotap_logo.svg), [light](https://core.twotap.com/logos/twotap_logo_light.svg), [dark](https://core.twotap.com/logos/twotap_logo_dark.svg). The ToS link is https://twotap.com/terms-intl, and the Privacy link is https://twotap.com/privacy. [block:image] { "images": [ { "image": [ "https://files.readme.io/YnTaRdMYTYStviBBZcu8_mb-tt-tos-variations.png", "mb-tt-tos-variations.png", "1500", "2024", "#e45362", "" ] } ] } [/block]
The only thing you have to test is the confirm callback. Before finalizing the order we ping your server ensure that it's actually you placing the order, and not someone else using your public token. Callbacks are also a convenient way of storing important information about the purchase on your end. Depending on what confirm mode you are using (the default mode is SMS), see the SMS API or HTTP API confirm flows, with example code on how to implement the callbacks. We provide an easy way to test out the confirm callbacks once you've implemented them. Use following snippet: [block:code] { "codes": [ { "code": "bash <(curl -s https://core.twotap.com/callback_test.sh) http://YOUR_LOCAL_MACHINE/PATH_TO_CONFIRM_CALLBACK http://YOUR_LOCAL_MACHINE/PATH_TO_UPDATE_CALLBACK", "language": "text", "name": null } ] } [/block] [block:callout] { "type": "warning", "title": "", "body": "Make sure the snippet above returns OK and that your callback endpoints are internet accessible before placing any orders." } [/block] Once everything is set up try placing an order with test_mode=fake_confirm. In 'fake_confirm' test mode the API will start the purchase as usual on the retailer site, except at the final 'Purchase Confirm' step it will return a fake OK and not place the order. [block:callout] { "type": "info", "title": "", "body": "It's important to note that some stores validate payment information when the order is actually placed, consequently the sms_update_url will be called directly with payment errors." } [/block] If you want to debug callbacks on your local machine use [ngrok](https://ngrok.com/). [block:api-header] { "type": "basic", "title": "International ToS Approval Box" } [/block] In the case of international orders, for legal compliance reasons, it's mandatory that all apps display a warning during checkout that the order is being fulfilled by Two Tap. Below you can find some mockups. You can find the different Two Tap logos in SVG format here: [standard](https://core.twotap.com/logos/twotap_logo.svg), [light](https://core.twotap.com/logos/twotap_logo_light.svg), [dark](https://core.twotap.com/logos/twotap_logo_dark.svg). The ToS link is https://twotap.com/terms-intl, and the Privacy link is https://twotap.com/privacy. [block:image] { "images": [ { "image": [ "https://files.readme.io/YnTaRdMYTYStviBBZcu8_mb-tt-tos-variations.png", "mb-tt-tos-variations.png", "1500", "2024", "#e45362", "" ] } ] } [/block]
{"category":"57780374ea758f0e00e6f821","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f82a","createdAt":"2015-07-09T23:52:03.940Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":21,"body":"See complete checkout flows in different programming languages in this [github repository](https://github.com/sradu/twotap-examples).","excerpt":"","slug":"examples","type":"basic","title":"Examples","__v":0,"childrenPages":[]}

Examples


See complete checkout flows in different programming languages in this [github repository](https://github.com/sradu/twotap-examples).
See complete checkout flows in different programming languages in this [github repository](https://github.com/sradu/twotap-examples).
{"__v":2,"_id":"57780374ea758f0e00e6f82b","api":{"auth":"required","params":[],"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","url":""},"body":"Two Tap works with a lot of merchants and as such we require a lot of input data. We've standardized them to ensure that the information you have to send is consistent on all purchases.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Possible keys\"\n}\n[/block]\nShipping information\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"email\",\n    \"0-1\": \"shipping_first_name\",\n    \"0-2\": \"shipping_last_name\",\n    \"0-3\": \"shipping_address\",\n    \"0-4\": \"\",\n    \"h-0\": \"Shipping\",\n    \"1-0\": \"shipping_city\",\n    \"1-1\": \"shipping_state\",\n    \"1-2\": \"shipping_zip\",\n    \"1-3\": \"shipping_country\",\n    \"1-4\": \"\",\n    \"2-0\": \"shipping_telephone\",\n    \"2-1\": \"\"\n  },\n  \"cols\": 4,\n  \"rows\": 3\n}\n[/block]\nPayment information\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"payment\",\n    \"0-0\": \"card_type\",\n    \"0-1\": \"card_number\",\n    \"0-2\": \"card_name\",\n    \"0-3\": \"expiry_date_year\",\n    \"0-4\": \"\",\n    \"1-4\": \"\",\n    \"2-4\": \"\",\n    \"2-3\": \"billing_zip\",\n    \"1-3\": \"billing_last_name\",\n    \"2-2\": \"billing_state\",\n    \"1-2\": \"billing_first_name\",\n    \"2-1\": \"billing_city\",\n    \"1-1\": \"cvv\",\n    \"1-0\": \"expiry_date_month\",\n    \"2-0\": \"billing_address\",\n    \"3-0\": \"billing_country\",\n    \"3-1\": \"billing_telephone\",\n    \"3-2\": \"\"\n  },\n  \"cols\": 4,\n  \"rows\": 4\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Possible values\"\n}\n[/block]\nThe fields listed here require data in the format below. If you don't respect this you will break user's wallets.\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"Visa\",\n    \"h-0\": \"card_type\",\n    \"0-1\": \"Mastercard\",\n    \"0-2\": \"American Express\",\n    \"0-3\": \"\"\n  },\n  \"cols\": 3,\n  \"rows\": 1\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"expiry_date_month\",\n    \"0-0\": \"01\",\n    \"0-1\": \"02\",\n    \"0-2\": \"03\",\n    \"0-3\": \"04\",\n    \"0-4\": \"05\",\n    \"1-0\": \"06\",\n    \"1-1\": \"07\",\n    \"1-2\": \"08\",\n    \"1-3\": \"09\",\n    \"1-4\": \"10\",\n    \"2-0\": \"11\",\n    \"2-1\": \"12\"\n  },\n  \"cols\": 5,\n  \"rows\": 3\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"expiry_date_year\",\n    \"0-0\": \"2016\",\n    \"0-1\": \"2017\",\n    \"0-2\": \"2018\",\n    \"0-3\": \"2019\",\n    \"0-4\": \"2017\",\n    \"1-0\": \"2020\",\n    \"1-1\": \"2021\",\n    \"1-2\": \"2022\",\n    \"1-3\": \"2023\",\n    \"1-4\": \"2022\",\n    \"2-0\": \"2024\",\n    \"2-1\": \"2025\",\n    \"2-2\": \"2026\"\n  },\n  \"cols\": 5,\n  \"rows\": 3\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"shipping_country, billing_country\",\n    \"0-0\": \"United States of America\\n(domestic only)\",\n    \"2-0\": \"Andorra\",\n    \"3-0\": \"Argentina\",\n    \"4-0\": \"Azerbaijan\",\n    \"5-0\": \"Belarus\",\n    \"6-0\": \"Bhutan\",\n    \"7-0\": \"Brazil\",\n    \"8-0\": \"Burundi\",\n    \"9-0\": \"Cayman Islands\",\n    \"10-0\": \"Christmas Island\",\n    \"11-0\": \"Congo, The Democratic Republic Of The\",\n    \"12-0\": \"Cuba\",\n    \"13-0\": \"Dominica\",\n    \"14-0\": \"El Salvador\",\n    \"15-0\": \"Falkland Islands (Malvinas)\",\n    \"16-0\": \"French Guiana\",\n    \"17-0\": \"Germany\",\n    \"18-0\": \"Grenada\",\n    \"19-0\": \"Guinea-Bissau\",\n    \"20-0\": \"Hong Kong\",\n    \"21-0\": \"Iran\",\n    \"22-0\": \"Italy\",\n    \"23-0\": \"Kenya\",\n    \"24-0\": \"Latvia\",\n    \"25-0\": \"Liechtenstein\",\n    \"26-0\": \"Madagascar\",\n    \"27-0\": \"Malta\",\n    \"28-0\": \"Mayotte\",\n    \"29-0\": \"Mongolia\",\n    \"30-0\": \"Myanmar\",\n    \"31-0\": \"Netherlands Antilles\",\n    \"32-0\": \"Nigeria\",\n    \"33-0\": \"Norway\",\n    \"34-0\": \"Panama\",\n    \"35-0\": \"Pitcairn\",\n    \"36-0\": \"Reunion\",\n    \"37-0\": \"Saint Lucia\",\n    \"38-0\": \"Saudi Arabia\",\n    \"39-0\": \"Sierra Leone\",\n    \"40-0\": \"Somalia\",\n    \"41-0\": \"Spain - Canary Islands\",\n    \"42-0\": \"Sudan\",\n    \"43-0\": \"Switzerland\",\n    \"44-0\": \"Tanzania, United Republic Of\",\n    \"45-0\": \"Trinidad And Tobago\",\n    \"46-0\": \"Tuvalu\",\n    \"47-0\": \"United Kingdom - Guernsey\",\n    \"48-0\": \"Uzbekistan\",\n    \"49-0\": \"Virgin Islands (British)\",\n    \"50-0\": \"Zambia\",\n    \"50-1\": \"Zimbabwe\",\n    \"49-1\": \"Virgin Islands (U.S)\",\n    \"48-1\": \"Vanuatu\",\n    \"47-1\": \"United Kingdom - Jersey\",\n    \"46-1\": \"Uganda\",\n    \"45-1\": \"Tunisia\",\n    \"44-1\": \"Thailand\",\n    \"43-1\": \"Syrian Arab Republic\",\n    \"0-1\": \"Canada\\n(domestic only)\",\n    \"0-2\": \"United Kingdom\\n(domestic only)\",\n    \"0-3\": \"\",\n    \"1-0\": \"Australia\\n(domestic only)\",\n    \"1-1\": \"Ireland\\n(domestic only)\",\n    \"1-2\": \"Japan\\n(international only)\"\n  },\n  \"cols\": 3,\n  \"rows\": 2\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"United States of America specific fields\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"USA shipping_state, billing_state\",\n    \"0-0\": \"Alabama\",\n    \"0-1\": \"Alaska\",\n    \"0-2\": \"Arizona\",\n    \"0-3\": \"Arkansas\",\n    \"1-0\": \"Armed Forces Americas\",\n    \"1-1\": \"Armed Forces Europe\",\n    \"1-2\": \"Armed Forces Pacific\",\n    \"1-3\": \"California\",\n    \"2-0\": \"Colorado\",\n    \"2-1\": \"Connecticut\",\n    \"2-2\": \"Delaware\",\n    \"2-3\": \"Florida\",\n    \"3-0\": \"Georgia\",\n    \"3-1\": \"Hawaii\",\n    \"3-2\": \"Idaho\",\n    \"3-3\": \"Illinois\",\n    \"4-0\": \"Indiana\",\n    \"4-1\": \"Iowa\",\n    \"4-2\": \"Kansas\",\n    \"4-3\": \"Kentucky\",\n    \"5-0\": \"Louisiana\",\n    \"5-1\": \"Maine\",\n    \"5-2\": \"Maryland\",\n    \"5-3\": \"Massachusetts\",\n    \"6-0\": \"Michigan\",\n    \"6-1\": \"Minnesota\",\n    \"6-2\": \"Mississippi\",\n    \"6-3\": \"Missouri\",\n    \"7-0\": \"Montana\",\n    \"7-1\": \"Nebraska\",\n    \"7-2\": \"Nevada\",\n    \"7-3\": \"New Hampshire\",\n    \"8-0\": \"New Jersey\",\n    \"8-1\": \"New Mexico\",\n    \"8-2\": \"New York\",\n    \"8-3\": \"North Carolina\",\n    \"9-0\": \"North Dakota\",\n    \"9-1\": \"Ohio\",\n    \"9-2\": \"Oklahoma\",\n    \"9-3\": \"Oregon\",\n    \"10-0\": \"Pennsylvania\",\n    \"10-1\": \"Rhode Island\",\n    \"10-2\": \"South Carolina\",\n    \"10-3\": \"South Dakota\",\n    \"11-0\": \"Tennessee\",\n    \"11-1\": \"Texas\",\n    \"11-2\": \"Utah\",\n    \"11-3\": \"Vermont\",\n    \"12-0\": \"Virginia\",\n    \"12-1\": \"Washington\",\n    \"12-2\": \"West Virginia\",\n    \"12-3\": \"Wisconsin\",\n    \"13-0\": \"Wyoming\",\n    \"13-1\": \"District of Columbia\"\n  },\n  \"cols\": 4,\n  \"rows\": 14\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Canada specific fields\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Canada shipping_state, billing_state\",\n    \"0-0\": \"Alberta\",\n    \"0-1\": \"British Columbia\",\n    \"0-2\": \"Manitoba\",\n    \"0-3\": \"New Brunswick\",\n    \"1-0\": \"Newfoundland/Labrador\",\n    \"1-1\": \"Northwest Territories\",\n    \"1-2\": \"Nova Scotia\",\n    \"1-3\": \"Nunavut\",\n    \"2-0\": \"Ontario\",\n    \"2-1\": \"Prince Edward Island\",\n    \"2-2\": \"Quebec\",\n    \"2-3\": \"Saskatchewan\",\n    \"3-0\": \"Yukon\"\n  },\n  \"cols\": 4,\n  \"rows\": 4\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"United Kingdom specific fields\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"United Kingdom shipping_state, billing_state\",\n    \"0-0\": \"Aberdeenshire\",\n    \"0-1\": \"Argyllshire\",\n    \"0-2\": \"Anglesey\",\n    \"0-3\": \"Armagh\",\n    \"1-0\": \"Angus/Forfarshire\",\n    \"1-1\": \"Antrim\",\n    \"1-2\": \"Ayrshire\",\n    \"1-3\": \"Bedfordshire\",\n    \"2-0\": \"Banffshire\",\n    \"2-1\": \"Berkshire\",\n    \"2-2\": \"Brecknockshire\",\n    \"2-3\": \"Bath&NthEstSomerset\",\n    \"3-0\": \"Buteshire\",\n    \"3-1\": \"Buckinghamshire\",\n    \"3-2\": \"Berwickshire\",\n    \"3-3\": \"Cambridgeshire\",\n    \"4-0\": \"Carmarthenshire\",\n    \"4-1\": \"Cardiganshire\",\n    \"4-2\": \"Caernarfonshire\",\n    \"4-3\": \"Cheshire\",\n    \"5-0\": \"Cromartyshire\",\n    \"5-1\": \"Clackmannanshire\",\n    \"5-2\": \"Cornwall\",\n    \"5-3\": \"Caithness\",\n    \"6-0\": \"Cumberland\",\n    \"6-1\": \"Derbyshire\",\n    \"6-2\": \"Denbighshire\",\n    \"6-3\": \"Dumfriesshire\",\n    \"7-0\": \"Down\",\n    \"7-1\": \"Dorset\",\n    \"7-2\": \"Dunbartonshire\",\n    \"7-3\": \"Durham\",\n    \"8-0\": \"Devon\",\n    \"8-1\": \"East Lothian\",\n    \"8-2\": \"Essex\",\n    \"8-3\": \"Fife\",\n    \"9-0\": \"Flintshire\",\n    \"9-1\": \"Fermanagh\",\n    \"9-2\": \"Gloucestershire\",\n    \"9-3\": \"Glamorgan\",\n    \"10-0\": \"Hampshire\",\n    \"10-1\": \"Hertfordshire\",\n    \"10-2\": \"Huntingdonshire\",\n    \"10-3\": \"Hereford and Worcs.\",\n    \"11-0\": \"Isle of Islay\",\n    \"11-1\": \"Isle of Lewis\",\n    \"11-2\": \"Isle of Man\",\n    \"11-3\": \"Invernesshire\",\n    \"12-0\": \"Isle of Skye\",\n    \"12-1\": \"Isle of Wight\",\n    \"12-2\": \"Isle of Scilly\",\n    \"12-3\": \"Kent\",\n    \"13-0\": \"Kincardineshire\",\n    \"13-1\": \"Kirkcudbrightshire\",\n    \"13-2\": \"Kinross-shire\",\n    \"13-3\": \"Lancashire\",\n    \"14-0\": \"London, City of\",\n    \"14-1\": \"Leicestershire\",\n    \"14-2\": \"Lincolnshire\",\n    \"14-3\": \"Lanarkshire\",\n    \"15-0\": \"London\",\n    \"15-1\": \"Midlothian\",\n    \"15-2\": \"Merioneth\",\n    \"15-3\": \"Mid Glamorgan\",\n    \"16-0\": \"Monmouthshire\",\n    \"16-1\": \"Morayshire\",\n    \"16-2\": \"Montgomeryshire\",\n    \"16-3\": \"Middlesex\",\n    \"17-0\": \"Northamptonshire\",\n    \"17-1\": \"Norfolk\",\n    \"17-2\": \"Nairnshire\",\n    \"17-3\": \"Nottinghamshire\",\n    \"18-0\": \"Northumberland\",\n    \"18-1\": \"Orkney\",\n    \"18-2\": \"Oxfordshire\",\n    \"18-3\": \"Peeblesshire\",\n    \"19-0\": \"Pembrokeshire\",\n    \"19-1\": \"Perthshire\",\n    \"19-2\": \"Radnorshire\",\n    \"19-3\": \"Renfrewshire\",\n    \"20-0\": \"Ross-shire\",\n    \"20-1\": \"Rutland\",\n    \"20-2\": \"Roxburghshire\",\n    \"20-3\": \"East Sussex\",\n    \"21-0\": \"Selkirkshire\",\n    \"21-1\": \"South Glamorgan\",\n    \"21-2\": \"Shropshire\",\n    \"21-3\": \"Suffolk\",\n    \"22-0\": \"Shetland\",\n    \"22-1\": \"Somerset\",\n    \"22-2\": \"Staffordshire\",\n    \"22-3\": \"Sutherland\",\n    \"23-0\": \"Stirlingshire\",\n    \"23-1\": \"West Sussex\",\n    \"23-2\": \"Sussex\",\n    \"23-3\": \"Surrey\",\n    \"24-0\": \"Tyrone\",\n    \"24-1\": \"Warwickshire\",\n    \"24-2\": \"Worcestershire\",\n    \"24-3\": \"Westmorland\",\n    \"25-0\": \"West Glamorgan\",\n    \"25-1\": \"Wiltshire\",\n    \"25-2\": \"West Lothian\",\n    \"25-3\": \"Wigtownshire\",\n    \"26-0\": \"North Yorkshire\",\n    \"26-1\": \"Yorkshire\",\n    \"26-2\": \"South Yorkshire\",\n    \"26-3\": \"West Yorkshire\",\n    \"27-0\": \"West Midlands\"\n  },\n  \"cols\": 4,\n  \"rows\": 28\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Australia specific fields\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Australia shipping_state, billing_state\",\n    \"0-0\": \"Australian Capital Territory\",\n    \"0-1\": \"New South Wales\",\n    \"0-2\": \"Northern Territory\",\n    \"0-3\": \"Queensland\",\n    \"1-0\": \"South Australia\",\n    \"1-1\": \"Tasmania\",\n    \"1-2\": \"Victoria\",\n    \"1-3\": \"Western Australia\"\n  },\n  \"cols\": 4,\n  \"rows\": 2\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Ireland specific fields\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Ireland shipping_state, billing_state\",\n    \"0-0\": \"Carlow\",\n    \"0-1\": \"Cavan\",\n    \"0-2\": \"Clare\",\n    \"0-3\": \"Cork\",\n    \"1-0\": \"Donegal\",\n    \"1-1\": \"Dublin\",\n    \"1-2\": \"Galway\",\n    \"1-3\": \"Kerry\",\n    \"2-0\": \"Kildare\",\n    \"2-1\": \"Kilkenny\",\n    \"2-2\": \"Laois\",\n    \"2-3\": \"Leitrim\",\n    \"3-0\": \"Limerick\",\n    \"3-1\": \"Longford\",\n    \"3-2\": \"Louth\",\n    \"3-3\": \"Mayo\",\n    \"4-0\": \"Meath\",\n    \"4-1\": \"Monaghan\",\n    \"4-2\": \"Offaly\",\n    \"4-3\": \"Roscommon\",\n    \"5-0\": \"Sligo\",\n    \"5-1\": \"Tipperary\",\n    \"5-2\": \"Waterford\",\n    \"5-3\": \"Westmeath\",\n    \"6-0\": \"Wexford\",\n    \"6-1\": \"Wicklow\"\n  },\n  \"cols\": 4,\n  \"rows\": 7\n}\n[/block]","category":"57780374ea758f0e00e6f821","createdAt":"2015-07-10T20:56:38.765Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":22,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"possible-keys-and-values","sync_unique":"","title":"Possible keys and values","type":"basic","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

Possible keys and values


Two Tap works with a lot of merchants and as such we require a lot of input data. We've standardized them to ensure that the information you have to send is consistent on all purchases. [block:api-header] { "type": "basic", "title": "Possible keys" } [/block] Shipping information [block:parameters] { "data": { "0-0": "email", "0-1": "shipping_first_name", "0-2": "shipping_last_name", "0-3": "shipping_address", "0-4": "", "h-0": "Shipping", "1-0": "shipping_city", "1-1": "shipping_state", "1-2": "shipping_zip", "1-3": "shipping_country", "1-4": "", "2-0": "shipping_telephone", "2-1": "" }, "cols": 4, "rows": 3 } [/block] Payment information [block:parameters] { "data": { "h-0": "payment", "0-0": "card_type", "0-1": "card_number", "0-2": "card_name", "0-3": "expiry_date_year", "0-4": "", "1-4": "", "2-4": "", "2-3": "billing_zip", "1-3": "billing_last_name", "2-2": "billing_state", "1-2": "billing_first_name", "2-1": "billing_city", "1-1": "cvv", "1-0": "expiry_date_month", "2-0": "billing_address", "3-0": "billing_country", "3-1": "billing_telephone", "3-2": "" }, "cols": 4, "rows": 4 } [/block] [block:api-header] { "type": "basic", "title": "Possible values" } [/block] The fields listed here require data in the format below. If you don't respect this you will break user's wallets. [block:parameters] { "data": { "0-0": "Visa", "h-0": "card_type", "0-1": "Mastercard", "0-2": "American Express", "0-3": "" }, "cols": 3, "rows": 1 } [/block] [block:parameters] { "data": { "h-0": "expiry_date_month", "0-0": "01", "0-1": "02", "0-2": "03", "0-3": "04", "0-4": "05", "1-0": "06", "1-1": "07", "1-2": "08", "1-3": "09", "1-4": "10", "2-0": "11", "2-1": "12" }, "cols": 5, "rows": 3 } [/block] [block:parameters] { "data": { "h-0": "expiry_date_year", "0-0": "2016", "0-1": "2017", "0-2": "2018", "0-3": "2019", "0-4": "2017", "1-0": "2020", "1-1": "2021", "1-2": "2022", "1-3": "2023", "1-4": "2022", "2-0": "2024", "2-1": "2025", "2-2": "2026" }, "cols": 5, "rows": 3 } [/block] [block:parameters] { "data": { "h-0": "shipping_country, billing_country", "0-0": "United States of America\n(domestic only)", "2-0": "Andorra", "3-0": "Argentina", "4-0": "Azerbaijan", "5-0": "Belarus", "6-0": "Bhutan", "7-0": "Brazil", "8-0": "Burundi", "9-0": "Cayman Islands", "10-0": "Christmas Island", "11-0": "Congo, The Democratic Republic Of The", "12-0": "Cuba", "13-0": "Dominica", "14-0": "El Salvador", "15-0": "Falkland Islands (Malvinas)", "16-0": "French Guiana", "17-0": "Germany", "18-0": "Grenada", "19-0": "Guinea-Bissau", "20-0": "Hong Kong", "21-0": "Iran", "22-0": "Italy", "23-0": "Kenya", "24-0": "Latvia", "25-0": "Liechtenstein", "26-0": "Madagascar", "27-0": "Malta", "28-0": "Mayotte", "29-0": "Mongolia", "30-0": "Myanmar", "31-0": "Netherlands Antilles", "32-0": "Nigeria", "33-0": "Norway", "34-0": "Panama", "35-0": "Pitcairn", "36-0": "Reunion", "37-0": "Saint Lucia", "38-0": "Saudi Arabia", "39-0": "Sierra Leone", "40-0": "Somalia", "41-0": "Spain - Canary Islands", "42-0": "Sudan", "43-0": "Switzerland", "44-0": "Tanzania, United Republic Of", "45-0": "Trinidad And Tobago", "46-0": "Tuvalu", "47-0": "United Kingdom - Guernsey", "48-0": "Uzbekistan", "49-0": "Virgin Islands (British)", "50-0": "Zambia", "50-1": "Zimbabwe", "49-1": "Virgin Islands (U.S)", "48-1": "Vanuatu", "47-1": "United Kingdom - Jersey", "46-1": "Uganda", "45-1": "Tunisia", "44-1": "Thailand", "43-1": "Syrian Arab Republic", "0-1": "Canada\n(domestic only)", "0-2": "United Kingdom\n(domestic only)", "0-3": "", "1-0": "Australia\n(domestic only)", "1-1": "Ireland\n(domestic only)", "1-2": "Japan\n(international only)" }, "cols": 3, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "United States of America specific fields" } [/block] [block:parameters] { "data": { "h-0": "USA shipping_state, billing_state", "0-0": "Alabama", "0-1": "Alaska", "0-2": "Arizona", "0-3": "Arkansas", "1-0": "Armed Forces Americas", "1-1": "Armed Forces Europe", "1-2": "Armed Forces Pacific", "1-3": "California", "2-0": "Colorado", "2-1": "Connecticut", "2-2": "Delaware", "2-3": "Florida", "3-0": "Georgia", "3-1": "Hawaii", "3-2": "Idaho", "3-3": "Illinois", "4-0": "Indiana", "4-1": "Iowa", "4-2": "Kansas", "4-3": "Kentucky", "5-0": "Louisiana", "5-1": "Maine", "5-2": "Maryland", "5-3": "Massachusetts", "6-0": "Michigan", "6-1": "Minnesota", "6-2": "Mississippi", "6-3": "Missouri", "7-0": "Montana", "7-1": "Nebraska", "7-2": "Nevada", "7-3": "New Hampshire", "8-0": "New Jersey", "8-1": "New Mexico", "8-2": "New York", "8-3": "North Carolina", "9-0": "North Dakota", "9-1": "Ohio", "9-2": "Oklahoma", "9-3": "Oregon", "10-0": "Pennsylvania", "10-1": "Rhode Island", "10-2": "South Carolina", "10-3": "South Dakota", "11-0": "Tennessee", "11-1": "Texas", "11-2": "Utah", "11-3": "Vermont", "12-0": "Virginia", "12-1": "Washington", "12-2": "West Virginia", "12-3": "Wisconsin", "13-0": "Wyoming", "13-1": "District of Columbia" }, "cols": 4, "rows": 14 } [/block] [block:api-header] { "type": "basic", "title": "Canada specific fields" } [/block] [block:parameters] { "data": { "h-0": "Canada shipping_state, billing_state", "0-0": "Alberta", "0-1": "British Columbia", "0-2": "Manitoba", "0-3": "New Brunswick", "1-0": "Newfoundland/Labrador", "1-1": "Northwest Territories", "1-2": "Nova Scotia", "1-3": "Nunavut", "2-0": "Ontario", "2-1": "Prince Edward Island", "2-2": "Quebec", "2-3": "Saskatchewan", "3-0": "Yukon" }, "cols": 4, "rows": 4 } [/block] [block:api-header] { "type": "basic", "title": "United Kingdom specific fields" } [/block] [block:parameters] { "data": { "h-0": "United Kingdom shipping_state, billing_state", "0-0": "Aberdeenshire", "0-1": "Argyllshire", "0-2": "Anglesey", "0-3": "Armagh", "1-0": "Angus/Forfarshire", "1-1": "Antrim", "1-2": "Ayrshire", "1-3": "Bedfordshire", "2-0": "Banffshire", "2-1": "Berkshire", "2-2": "Brecknockshire", "2-3": "Bath&NthEstSomerset", "3-0": "Buteshire", "3-1": "Buckinghamshire", "3-2": "Berwickshire", "3-3": "Cambridgeshire", "4-0": "Carmarthenshire", "4-1": "Cardiganshire", "4-2": "Caernarfonshire", "4-3": "Cheshire", "5-0": "Cromartyshire", "5-1": "Clackmannanshire", "5-2": "Cornwall", "5-3": "Caithness", "6-0": "Cumberland", "6-1": "Derbyshire", "6-2": "Denbighshire", "6-3": "Dumfriesshire", "7-0": "Down", "7-1": "Dorset", "7-2": "Dunbartonshire", "7-3": "Durham", "8-0": "Devon", "8-1": "East Lothian", "8-2": "Essex", "8-3": "Fife", "9-0": "Flintshire", "9-1": "Fermanagh", "9-2": "Gloucestershire", "9-3": "Glamorgan", "10-0": "Hampshire", "10-1": "Hertfordshire", "10-2": "Huntingdonshire", "10-3": "Hereford and Worcs.", "11-0": "Isle of Islay", "11-1": "Isle of Lewis", "11-2": "Isle of Man", "11-3": "Invernesshire", "12-0": "Isle of Skye", "12-1": "Isle of Wight", "12-2": "Isle of Scilly", "12-3": "Kent", "13-0": "Kincardineshire", "13-1": "Kirkcudbrightshire", "13-2": "Kinross-shire", "13-3": "Lancashire", "14-0": "London, City of", "14-1": "Leicestershire", "14-2": "Lincolnshire", "14-3": "Lanarkshire", "15-0": "London", "15-1": "Midlothian", "15-2": "Merioneth", "15-3": "Mid Glamorgan", "16-0": "Monmouthshire", "16-1": "Morayshire", "16-2": "Montgomeryshire", "16-3": "Middlesex", "17-0": "Northamptonshire", "17-1": "Norfolk", "17-2": "Nairnshire", "17-3": "Nottinghamshire", "18-0": "Northumberland", "18-1": "Orkney", "18-2": "Oxfordshire", "18-3": "Peeblesshire", "19-0": "Pembrokeshire", "19-1": "Perthshire", "19-2": "Radnorshire", "19-3": "Renfrewshire", "20-0": "Ross-shire", "20-1": "Rutland", "20-2": "Roxburghshire", "20-3": "East Sussex", "21-0": "Selkirkshire", "21-1": "South Glamorgan", "21-2": "Shropshire", "21-3": "Suffolk", "22-0": "Shetland", "22-1": "Somerset", "22-2": "Staffordshire", "22-3": "Sutherland", "23-0": "Stirlingshire", "23-1": "West Sussex", "23-2": "Sussex", "23-3": "Surrey", "24-0": "Tyrone", "24-1": "Warwickshire", "24-2": "Worcestershire", "24-3": "Westmorland", "25-0": "West Glamorgan", "25-1": "Wiltshire", "25-2": "West Lothian", "25-3": "Wigtownshire", "26-0": "North Yorkshire", "26-1": "Yorkshire", "26-2": "South Yorkshire", "26-3": "West Yorkshire", "27-0": "West Midlands" }, "cols": 4, "rows": 28 } [/block] [block:api-header] { "type": "basic", "title": "Australia specific fields" } [/block] [block:parameters] { "data": { "h-0": "Australia shipping_state, billing_state", "0-0": "Australian Capital Territory", "0-1": "New South Wales", "0-2": "Northern Territory", "0-3": "Queensland", "1-0": "South Australia", "1-1": "Tasmania", "1-2": "Victoria", "1-3": "Western Australia" }, "cols": 4, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "Ireland specific fields" } [/block] [block:parameters] { "data": { "h-0": "Ireland shipping_state, billing_state", "0-0": "Carlow", "0-1": "Cavan", "0-2": "Clare", "0-3": "Cork", "1-0": "Donegal", "1-1": "Dublin", "1-2": "Galway", "1-3": "Kerry", "2-0": "Kildare", "2-1": "Kilkenny", "2-2": "Laois", "2-3": "Leitrim", "3-0": "Limerick", "3-1": "Longford", "3-2": "Louth", "3-3": "Mayo", "4-0": "Meath", "4-1": "Monaghan", "4-2": "Offaly", "4-3": "Roscommon", "5-0": "Sligo", "5-1": "Tipperary", "5-2": "Waterford", "5-3": "Westmeath", "6-0": "Wexford", "6-1": "Wicklow" }, "cols": 4, "rows": 7 } [/block]
Two Tap works with a lot of merchants and as such we require a lot of input data. We've standardized them to ensure that the information you have to send is consistent on all purchases. [block:api-header] { "type": "basic", "title": "Possible keys" } [/block] Shipping information [block:parameters] { "data": { "0-0": "email", "0-1": "shipping_first_name", "0-2": "shipping_last_name", "0-3": "shipping_address", "0-4": "", "h-0": "Shipping", "1-0": "shipping_city", "1-1": "shipping_state", "1-2": "shipping_zip", "1-3": "shipping_country", "1-4": "", "2-0": "shipping_telephone", "2-1": "" }, "cols": 4, "rows": 3 } [/block] Payment information [block:parameters] { "data": { "h-0": "payment", "0-0": "card_type", "0-1": "card_number", "0-2": "card_name", "0-3": "expiry_date_year", "0-4": "", "1-4": "", "2-4": "", "2-3": "billing_zip", "1-3": "billing_last_name", "2-2": "billing_state", "1-2": "billing_first_name", "2-1": "billing_city", "1-1": "cvv", "1-0": "expiry_date_month", "2-0": "billing_address", "3-0": "billing_country", "3-1": "billing_telephone", "3-2": "" }, "cols": 4, "rows": 4 } [/block] [block:api-header] { "type": "basic", "title": "Possible values" } [/block] The fields listed here require data in the format below. If you don't respect this you will break user's wallets. [block:parameters] { "data": { "0-0": "Visa", "h-0": "card_type", "0-1": "Mastercard", "0-2": "American Express", "0-3": "" }, "cols": 3, "rows": 1 } [/block] [block:parameters] { "data": { "h-0": "expiry_date_month", "0-0": "01", "0-1": "02", "0-2": "03", "0-3": "04", "0-4": "05", "1-0": "06", "1-1": "07", "1-2": "08", "1-3": "09", "1-4": "10", "2-0": "11", "2-1": "12" }, "cols": 5, "rows": 3 } [/block] [block:parameters] { "data": { "h-0": "expiry_date_year", "0-0": "2016", "0-1": "2017", "0-2": "2018", "0-3": "2019", "0-4": "2017", "1-0": "2020", "1-1": "2021", "1-2": "2022", "1-3": "2023", "1-4": "2022", "2-0": "2024", "2-1": "2025", "2-2": "2026" }, "cols": 5, "rows": 3 } [/block] [block:parameters] { "data": { "h-0": "shipping_country, billing_country", "0-0": "United States of America\n(domestic only)", "2-0": "Andorra", "3-0": "Argentina", "4-0": "Azerbaijan", "5-0": "Belarus", "6-0": "Bhutan", "7-0": "Brazil", "8-0": "Burundi", "9-0": "Cayman Islands", "10-0": "Christmas Island", "11-0": "Congo, The Democratic Republic Of The", "12-0": "Cuba", "13-0": "Dominica", "14-0": "El Salvador", "15-0": "Falkland Islands (Malvinas)", "16-0": "French Guiana", "17-0": "Germany", "18-0": "Grenada", "19-0": "Guinea-Bissau", "20-0": "Hong Kong", "21-0": "Iran", "22-0": "Italy", "23-0": "Kenya", "24-0": "Latvia", "25-0": "Liechtenstein", "26-0": "Madagascar", "27-0": "Malta", "28-0": "Mayotte", "29-0": "Mongolia", "30-0": "Myanmar", "31-0": "Netherlands Antilles", "32-0": "Nigeria", "33-0": "Norway", "34-0": "Panama", "35-0": "Pitcairn", "36-0": "Reunion", "37-0": "Saint Lucia", "38-0": "Saudi Arabia", "39-0": "Sierra Leone", "40-0": "Somalia", "41-0": "Spain - Canary Islands", "42-0": "Sudan", "43-0": "Switzerland", "44-0": "Tanzania, United Republic Of", "45-0": "Trinidad And Tobago", "46-0": "Tuvalu", "47-0": "United Kingdom - Guernsey", "48-0": "Uzbekistan", "49-0": "Virgin Islands (British)", "50-0": "Zambia", "50-1": "Zimbabwe", "49-1": "Virgin Islands (U.S)", "48-1": "Vanuatu", "47-1": "United Kingdom - Jersey", "46-1": "Uganda", "45-1": "Tunisia", "44-1": "Thailand", "43-1": "Syrian Arab Republic", "0-1": "Canada\n(domestic only)", "0-2": "United Kingdom\n(domestic only)", "0-3": "", "1-0": "Australia\n(domestic only)", "1-1": "Ireland\n(domestic only)", "1-2": "Japan\n(international only)" }, "cols": 3, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "United States of America specific fields" } [/block] [block:parameters] { "data": { "h-0": "USA shipping_state, billing_state", "0-0": "Alabama", "0-1": "Alaska", "0-2": "Arizona", "0-3": "Arkansas", "1-0": "Armed Forces Americas", "1-1": "Armed Forces Europe", "1-2": "Armed Forces Pacific", "1-3": "California", "2-0": "Colorado", "2-1": "Connecticut", "2-2": "Delaware", "2-3": "Florida", "3-0": "Georgia", "3-1": "Hawaii", "3-2": "Idaho", "3-3": "Illinois", "4-0": "Indiana", "4-1": "Iowa", "4-2": "Kansas", "4-3": "Kentucky", "5-0": "Louisiana", "5-1": "Maine", "5-2": "Maryland", "5-3": "Massachusetts", "6-0": "Michigan", "6-1": "Minnesota", "6-2": "Mississippi", "6-3": "Missouri", "7-0": "Montana", "7-1": "Nebraska", "7-2": "Nevada", "7-3": "New Hampshire", "8-0": "New Jersey", "8-1": "New Mexico", "8-2": "New York", "8-3": "North Carolina", "9-0": "North Dakota", "9-1": "Ohio", "9-2": "Oklahoma", "9-3": "Oregon", "10-0": "Pennsylvania", "10-1": "Rhode Island", "10-2": "South Carolina", "10-3": "South Dakota", "11-0": "Tennessee", "11-1": "Texas", "11-2": "Utah", "11-3": "Vermont", "12-0": "Virginia", "12-1": "Washington", "12-2": "West Virginia", "12-3": "Wisconsin", "13-0": "Wyoming", "13-1": "District of Columbia" }, "cols": 4, "rows": 14 } [/block] [block:api-header] { "type": "basic", "title": "Canada specific fields" } [/block] [block:parameters] { "data": { "h-0": "Canada shipping_state, billing_state", "0-0": "Alberta", "0-1": "British Columbia", "0-2": "Manitoba", "0-3": "New Brunswick", "1-0": "Newfoundland/Labrador", "1-1": "Northwest Territories", "1-2": "Nova Scotia", "1-3": "Nunavut", "2-0": "Ontario", "2-1": "Prince Edward Island", "2-2": "Quebec", "2-3": "Saskatchewan", "3-0": "Yukon" }, "cols": 4, "rows": 4 } [/block] [block:api-header] { "type": "basic", "title": "United Kingdom specific fields" } [/block] [block:parameters] { "data": { "h-0": "United Kingdom shipping_state, billing_state", "0-0": "Aberdeenshire", "0-1": "Argyllshire", "0-2": "Anglesey", "0-3": "Armagh", "1-0": "Angus/Forfarshire", "1-1": "Antrim", "1-2": "Ayrshire", "1-3": "Bedfordshire", "2-0": "Banffshire", "2-1": "Berkshire", "2-2": "Brecknockshire", "2-3": "Bath&NthEstSomerset", "3-0": "Buteshire", "3-1": "Buckinghamshire", "3-2": "Berwickshire", "3-3": "Cambridgeshire", "4-0": "Carmarthenshire", "4-1": "Cardiganshire", "4-2": "Caernarfonshire", "4-3": "Cheshire", "5-0": "Cromartyshire", "5-1": "Clackmannanshire", "5-2": "Cornwall", "5-3": "Caithness", "6-0": "Cumberland", "6-1": "Derbyshire", "6-2": "Denbighshire", "6-3": "Dumfriesshire", "7-0": "Down", "7-1": "Dorset", "7-2": "Dunbartonshire", "7-3": "Durham", "8-0": "Devon", "8-1": "East Lothian", "8-2": "Essex", "8-3": "Fife", "9-0": "Flintshire", "9-1": "Fermanagh", "9-2": "Gloucestershire", "9-3": "Glamorgan", "10-0": "Hampshire", "10-1": "Hertfordshire", "10-2": "Huntingdonshire", "10-3": "Hereford and Worcs.", "11-0": "Isle of Islay", "11-1": "Isle of Lewis", "11-2": "Isle of Man", "11-3": "Invernesshire", "12-0": "Isle of Skye", "12-1": "Isle of Wight", "12-2": "Isle of Scilly", "12-3": "Kent", "13-0": "Kincardineshire", "13-1": "Kirkcudbrightshire", "13-2": "Kinross-shire", "13-3": "Lancashire", "14-0": "London, City of", "14-1": "Leicestershire", "14-2": "Lincolnshire", "14-3": "Lanarkshire", "15-0": "London", "15-1": "Midlothian", "15-2": "Merioneth", "15-3": "Mid Glamorgan", "16-0": "Monmouthshire", "16-1": "Morayshire", "16-2": "Montgomeryshire", "16-3": "Middlesex", "17-0": "Northamptonshire", "17-1": "Norfolk", "17-2": "Nairnshire", "17-3": "Nottinghamshire", "18-0": "Northumberland", "18-1": "Orkney", "18-2": "Oxfordshire", "18-3": "Peeblesshire", "19-0": "Pembrokeshire", "19-1": "Perthshire", "19-2": "Radnorshire", "19-3": "Renfrewshire", "20-0": "Ross-shire", "20-1": "Rutland", "20-2": "Roxburghshire", "20-3": "East Sussex", "21-0": "Selkirkshire", "21-1": "South Glamorgan", "21-2": "Shropshire", "21-3": "Suffolk", "22-0": "Shetland", "22-1": "Somerset", "22-2": "Staffordshire", "22-3": "Sutherland", "23-0": "Stirlingshire", "23-1": "West Sussex", "23-2": "Sussex", "23-3": "Surrey", "24-0": "Tyrone", "24-1": "Warwickshire", "24-2": "Worcestershire", "24-3": "Westmorland", "25-0": "West Glamorgan", "25-1": "Wiltshire", "25-2": "West Lothian", "25-3": "Wigtownshire", "26-0": "North Yorkshire", "26-1": "Yorkshire", "26-2": "South Yorkshire", "26-3": "West Yorkshire", "27-0": "West Midlands" }, "cols": 4, "rows": 28 } [/block] [block:api-header] { "type": "basic", "title": "Australia specific fields" } [/block] [block:parameters] { "data": { "h-0": "Australia shipping_state, billing_state", "0-0": "Australian Capital Territory", "0-1": "New South Wales", "0-2": "Northern Territory", "0-3": "Queensland", "1-0": "South Australia", "1-1": "Tasmania", "1-2": "Victoria", "1-3": "Western Australia" }, "cols": 4, "rows": 2 } [/block] [block:api-header] { "type": "basic", "title": "Ireland specific fields" } [/block] [block:parameters] { "data": { "h-0": "Ireland shipping_state, billing_state", "0-0": "Carlow", "0-1": "Cavan", "0-2": "Clare", "0-3": "Cork", "1-0": "Donegal", "1-1": "Dublin", "1-2": "Galway", "1-3": "Kerry", "2-0": "Kildare", "2-1": "Kilkenny", "2-2": "Laois", "2-3": "Leitrim", "3-0": "Limerick", "3-1": "Longford", "3-2": "Louth", "3-3": "Mayo", "4-0": "Meath", "4-1": "Monaghan", "4-2": "Offaly", "4-3": "Roscommon", "5-0": "Sligo", "5-1": "Tipperary", "5-2": "Waterford", "5-3": "Westmeath", "6-0": "Wexford", "6-1": "Wicklow" }, "cols": 4, "rows": 7 } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f841","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\nproducts = [ \n  'http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605/#fae3AT5i',\n  'http://www.target.com/p/out-of-stock-product#aiQu2iLo' \n]\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\", { products: products }\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\ncurl https://api.twotap.com/v1.0/cart?public_token=$PUBLIC_TOKEN --header 'Content-Type: application/json' --data-binary '{\n  \"products\": [\"http://fab.com/sale/4850/product/11263/\", \"http://fab.com/sale/4800/product/43565/\"]\n}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\nPUBLIC_TOKEN = 'YOUR PUBLIC TOKEN'\n\npayload = {'products': [ 'http://fab.com/sale/4850/product/11263/', 'http://fab.com/sale/4800/product/43565/' ]}\n\nresponse = requests.post('https://api.twotap.com/v1.0/cart?public_token=' + PUBLIC_TOKEN,\n        data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(response.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN', { \n    \"products\": [ \"http://fab.com/sale/4850/product/11263/\", \"http://fab.com/sale/4800/product/43565/\" ]\n  }, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nrequest({\n  url: 'https://api.twotap.com/v1.0/cart?public_token=' + public_token,\n  json: { \"products\": [ \"http://fab.com/sale/4850/product/11263/\", \"http://fab.com/sale/4800/product/43565/\" ]},\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php \n\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$url = 'https://api.twotap.com/v1.0/cart?public_token='.$public_token;\n$products = array('products' => 'http://fab.com/sale/4850/product/11263/', 'http://fab.com/sale/4800/product/43565/');\n$response = Requests::post($url, array(), $products);\necho $response->body;\n\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    public_token := \"PUBLIC_TOKEN\"\n    url := \"https://api.twotap.com/v1.0/cart?public_token=\" + public_token\n    var jsonStr = []byte(`{\"products\":\"http://fab.com/sale/4850/product/11263/,http://fab.com/sale/4800/product/43565/\"}`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var public_token = \"PUBLIC_TOKEN\";\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/cart?public_token=\" + public_token);\n      dynamic payload = new ExpandoObject ();\n      payload.products = new String[] { \"http://fab.com/sale/4850/product/11263/\", \"http://fab.com/sale/4800/product/43565/\" };\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"params":[{"_id":"55a30cd550f0080d0016a87c","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"55a29d56a50aca1700782e93","ref":"","required":true,"desc":"A list of product URLs. Max 35 in one request, the API will silently drop anything above that.","default":"","type":"array_string","name":"products","in":"body"},{"_id":"55a29d56a50aca1700782e92","ref":"","required":false,"desc":"(Optional) An endpoint where Two Tap can POST the product information once the information is retrieved.","default":"","type":"string","name":"finished_url","in":"body"},{"_id":"5616f9177f74330d00dfd733","ref":"","required":false,"desc":"(Optional) If you set this to 'flat' the product attributes will be returned as an array instead of a tree. See /cart/status for more information.","default":"","type":"string","name":"finished_product_attributes_format","in":"body"},{"_id":"560da1128bfb03170030ac52","ref":"","required":false,"desc":"(Optional) You can send any information here and it will be attached to the cart and piped back with /status responses and callbacks.","default":"","type":"object","name":"notes","in":"body"},{"_id":"55a29d56a50aca1700782e91","ref":"","required":false,"desc":"(Optional) fake_confirm. A way to test the API the interface without making actual purchases.","default":"","type":"string","name":"test_mode","in":"body"},{"_id":"576d993fac579017000df004","ref":"","required":false,"desc":"(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds.","default":"300","type":"int","name":"cache_time","in":"body"},{"_id":"577810e0e577590e000e3dfe","ref":"","required":false,"desc":"(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country to receive prices in local currency.","default":"","type":"string","name":"destination_country","in":"body"}],"results":{"codes":[{"status":200,"language":"json","code":"{\n  \"cart_id\": \"50f414b9e6a4869bf6000009\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\"\n}                    ","name":""}]},"settings":"","url":"/cart"},"body":"The first request you have to make is to '/cart'. Send '/cart' a list of products and it will return product information (title, price, image) and the required fields that the user has to fill in to finalize the purchase.\n\nTo ease development it's recommended you append a random hash at the end of each URL. For instance, http://www.target.com/product#RANDOM. At /cart/status, Two Tap will return structured information about each product and you'll be able to match what you sent with the 'original_url' argument from the response.\n\nYou can not add products to an existing cart. If you'd like to add more products feel free to start a new '/cart' call.\n\nThis request is processed in the background. You either have to call '/cart/status' which will retrieve the relevant information once the job is finished, or set 'finished_url' which will trigger a callback to your servers.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Ideally, send /cart the actual product URLs (eg http://store.com/url). You can send affiliate links later on with /purchase.\\n\\nThat being said, /cart does accept and follow most affiliate links to try to find the actual product URL underneath. However, this can cause various confusions if you are expecting consistent product MD5s. Ideally, send a #RANDOM with affiliate links as well.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Response description\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"cart_id\",\n    \"0-1\": \"An ID to use when checking the cart status.\",\n    \"1-0\": \"message\",\n    \"1-1\": \"If Two Tap has completed the request: 'still_processing'.\",\n    \"2-1\": \"A more human-friendly description of the message.\",\n    \"2-0\": \"description\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T17:56:36.878Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":23,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"cart","sync_unique":"","title":"/cart","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/cart


Body JSON

public_token:
required
string
Your Two Tap public token.
products:
required
array of strings
A list of product URLs. Max 35 in one request, the API will silently drop anything above that.
finished_url:
string
(Optional) An endpoint where Two Tap can POST the product information once the information is retrieved.
finished_product_attributes_format:
string
(Optional) If you set this to 'flat' the product attributes will be returned as an array instead of a tree. See /cart/status for more information.
notes:
object
(Optional) You can send any information here and it will be attached to the cart and piped back with /status responses and callbacks.
test_mode:
string
(Optional) fake_confirm. A way to test the API the interface without making actual purchases.
cache_time:
integer300
(Optional) This controls how fresh you'd like Two Tap's product data to be. Please consult the 'Product Availability' section for more information. In seconds.
destination_country:
string
(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country to receive prices in local currency.
The first request you have to make is to '/cart'. Send '/cart' a list of products and it will return product information (title, price, image) and the required fields that the user has to fill in to finalize the purchase. To ease development it's recommended you append a random hash at the end of each URL. For instance, http://www.target.com/product#RANDOM. At /cart/status, Two Tap will return structured information about each product and you'll be able to match what you sent with the 'original_url' argument from the response. You can not add products to an existing cart. If you'd like to add more products feel free to start a new '/cart' call. This request is processed in the background. You either have to call '/cart/status' which will retrieve the relevant information once the job is finished, or set 'finished_url' which will trigger a callback to your servers. [block:callout] { "type": "warning", "body": "Ideally, send /cart the actual product URLs (eg http://store.com/url). You can send affiliate links later on with /purchase.\n\nThat being said, /cart does accept and follow most affiliate links to try to find the actual product URL underneath. However, this can cause various confusions if you are expecting consistent product MD5s. Ideally, send a #RANDOM with affiliate links as well." } [/block] [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "cart_id", "0-1": "An ID to use when checking the cart status.", "1-0": "message", "1-1": "If Two Tap has completed the request: 'still_processing'.", "2-1": "A more human-friendly description of the message.", "2-0": "description" }, "cols": 2, "rows": 3 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



The first request you have to make is to '/cart'. Send '/cart' a list of products and it will return product information (title, price, image) and the required fields that the user has to fill in to finalize the purchase. To ease development it's recommended you append a random hash at the end of each URL. For instance, http://www.target.com/product#RANDOM. At /cart/status, Two Tap will return structured information about each product and you'll be able to match what you sent with the 'original_url' argument from the response. You can not add products to an existing cart. If you'd like to add more products feel free to start a new '/cart' call. This request is processed in the background. You either have to call '/cart/status' which will retrieve the relevant information once the job is finished, or set 'finished_url' which will trigger a callback to your servers. [block:callout] { "type": "warning", "body": "Ideally, send /cart the actual product URLs (eg http://store.com/url). You can send affiliate links later on with /purchase.\n\nThat being said, /cart does accept and follow most affiliate links to try to find the actual product URL underneath. However, this can cause various confusions if you are expecting consistent product MD5s. Ideally, send a #RANDOM with affiliate links as well." } [/block] [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "cart_id", "0-1": "An ID to use when checking the cart status.", "1-0": "message", "1-1": "If Two Tap has completed the request: 'still_processing'.", "2-1": "A more human-friendly description of the message.", "2-0": "description" }, "cols": 2, "rows": 3 } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f842","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\ncart_id = ARGV[0]\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/cart/status?public_token=PUBLIC_TOKEN&cart_id=#{cart_id}\"\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nCART_ID=CART_ID\n\ncurl https://api.twotap.com/v1.0/cart/status?public_token=$PUBLIC_TOKEN\\&cart_id=$CART_ID","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\n\npublic_token = 'PUBLIC_TOKEN'\ncart_id = 'CART_ID'\nr = requests.get('https://api.twotap.com/v1.0/cart/status?public_token=' + public_token + '&cart_id=' + cart_id)\nprint(r.json())","language":"python"},{"code":"$.get(\"https://api.twotap.com/v1.0/cart/status?public_token=PUBLIC_TOKEN&cart_id=CART_ID\", function(data, status) {\n  console.log(data);\n})","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar cart_id = 'CART_ID';\nrequest({\n  url: 'https://api.twotap.com/v1.0/cart/status?public_token=' + public_token + '&cart_id=' + cart_id,\n  method: \"GET\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\n\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$cart_id = 'CART_ID';\n$url = 'https://api.twotap.com/v1.0/cart/status?public_token='.$public_token.'&cart_id='.$cart_id;\n$response = Requests::get($url);\necho $response->body;\n\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n)\n\nfunc main() {\n    public_token := \"PUBLIC_TOKEN\"\n    cart_id := \"CART_ID\"\n    url := \"https://api.twotap.com/v1.0/cart/status?public_token=\" + public_token + \"&cart_id=\" + cart_id\n    req, err := http.NewRequest(\"GET\", url, nil)\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var public_token = \"PUBLIC_TOKEN\";\n      var cart_id = \"CART_ID\";\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/cart/status?public_token=\" + public_token + \"&cart_id=\" + cart_id);\n      var result = client.GetAsync (\"\").Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"params":[{"_id":"55a30ce589d84c0d002af0ad","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"query"},{"_id":"55a29fcaa50aca1700782e95","ref":"","required":true,"desc":"The cart id that is sent by '/cart'.","default":"","type":"string","name":"cart_id","in":"query"},{"_id":"55d892229f93a917003dbe67","ref":"","required":false,"desc":"(Optional) If you set this to 'flat' the product attributes will be returned as an array instead of a tree.","default":"","type":"string","name":"product_attributes_format","in":"query"},{"_id":"55a29fcaa50aca1700782e94","ref":"","required":false,"desc":"(Optional) fake_confirm. A way to test the API the interface without making actual purchases.","default":"","type":"string","name":"test_mode","in":"query"},{"_id":"577811312a1c370e005b6853","ref":"","required":false,"desc":"(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country to receive prices in local currency.","default":"","type":"string","name":"destination_country","in":"query"}],"results":{"codes":[{"name":"still_processing","code":"{\n  \"sites\": {\n    \"5225da1055a0f96c8b000004\": {\n      \"cart\": {\n        \"e987cc0e00b50b6edb0b785ca0ce3efb\": {\n          \"last_message\": \"Fetching title.\",\n          \"percent_done\": 33.53819139596137,\n\t\t\t\t\t\"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n          \"status\": \"done\"\n        },\n        \"046d87a2152507c2055e0a5a369eb4b9\": {\n          \"last_message\": \"Fetching required fields.\",\n          \"percent_done\": 33.53819139596137,\n\t\t\t\t\t\t\"url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"status\": \"still_processing\"\n        }\n      },\n      \"info\": {\n        \"name\": \"Target\",\n        \"url\": \"target.com\"\n      }\n    }\n  },\n  \"cart_id\": \"511fa680692d5d9e06000001\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\"\n}","language":"json","status":200},{"code":"{\n  \"sites\": {\n    \"5225da1055a0f96c8b000004\": {\n      \"info\": {\n        \"logo\": \"https://core.twotap.com/system/sites/logos/5225/da10/55a0/f96c/8b00/0004/small/5225da1055a0f96c8b000004.png?1467509483762\",\n        \"name\": \"Target\",\n        \"url\": \"target.com\"\n      },\n      \"coupon_support\": true,\n      \"gift_card_support\": true,\n      \"checkout_support\": [\"noauthCheckout\", \"localCheckout\"],\n      \"shipping_countries_support\": [\"United States of America\", \"Japan\"],\n      \"billing_countries_support\": [\"United States of America\", \"Japan\"],\n      \"shipping_options\": {\n        \"cheapest\": \"Default shipping option\"\n      },\n      \"add_to_cart\": {\n        \"e987cc0e00b50b6edb0b785ca0ce3efb\": {\n          \"title\": \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\",\n          \"price\": \"$47.99\",\n          \"original_price\": \"$79.99\",\n          \"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n          \"alt_images\": [\"http://target.scene7.com/is/image/Target/12877464?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt01?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt02?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt03?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt04?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt05?wid=800\"],\n          \"description\": \"Product description\",\n          \"returns\": \"Return policy\",\n          \"categories\": [\"home\", \"dining & entertaining\", \"flatware\", \"flatware sets\", \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\"],\n          \"extra_info\": \"\",\n          \"pickup_support\": true,\n          \"required_field_values\": [\n            {\n              options: {\n                color: {\n                  value: \"http://scene7.targetimg1.com/is/image/16640462_Swatch\",\n                  text: \"Ebony\"\n                },\n                size: {\n                  value: \"2\",\n                  text: \"2\"\n                }\n              },\n              price: \"$29.99\",\n              image: \"http://scene7.targetimg1.com/is/image/16640454?wid=480&hei=480\",\n              extra_info: \"\",\n              alt_images: [\n                \"http://scene7.targetimg1.com/is/image/16640462\",\n                \"http://scene7.targetimg1.com/is/image/16640462_Alt01\"\n              ]\n            },\n            {\n              options: {\n                color: {\n                  value: \"http://scene7.targetimg1.com/is/image/16640462_Swatch\",\n                  text: \"Ebony\"\n                },\n                size: {\n                  value: \"4\",\n                  text: \"4\"\n                }\n              },\n              price: \"$29.99\",\n              image: \"http://scene7.targetimg1.com/is/image/16640455?wid=480&hei=480\",\n              extra_info: \"\",\n              alt_images: [\n                \"http://scene7.targetimg1.com/is/image/16640462\",\n                \"http://scene7.targetimg1.com/is/image/16640462_Alt01\"\n              ]\n            },\n            {\n              options: {\n                color: {\n                  value: \"http://scene7.targetimg1.com/is/image/16641944_Swatch\",\n                  text: \"Federal Blue\"\n                },\n                size: {\n                  value: \"4\",\n                  text: \"4\"\n                }\n              },\n              price: \"$29.99\",\n              image: \"http://scene7.targetimg1.com/is/image/16641971?wid=480&hei=480\",\n              extra_info: \"\",\n              alt_images: [\n                \"http://scene7.targetimg1.com/is/image/16641944\",\n                \"http://scene7.targetimg1.com/is/image/16641944_Alt01\"\n              ]\n            },\n          ],\n          \"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n          \"discounted_price\": null,\n          \"required_fields\": {\n            \"size\": {\n              \"data\": [{\n                \"input_name\": \"SELECT\",\n                \"input_type\": \"select-one\"\n              }]\n            },\n            \"quantity\": {\n              \"data\": [{\n                \"input_name\": \"INPUT\",\n                \"input_type\": \"text\"\n              }]\n            }\n          },\n          \"status\": \"done\",\n          \"weight\": \"1000\",\n          \"clean_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n          \"original_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\"\n        }\n      },\n      \"failed_to_add_to_cart\": {\n        \"046d87a2152507c2055e0a5a369eb4b9\": {\n          \"original_url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"clean_url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"status\": \"failed\",\n          \"discounted_price\": null,\n          \"original_price\": null,\n          \"price\": null,\n          \"pickup_support\": false,\n          \"image\": \"\",\n          \"url\": \"http://www.target.com/p/out-of-stock-product\",\n        }\n      }\n    }\n  },\n  \"user_id\": null,\n  \"unknown_urls\": [],\n  \"cart_id\": \"57786aebdfeb41503dcac297\",\n  \"country\": \"us\",\n  \"stored_field_values\": {},\n  \"message\": \"has_failures\",\n  \"description\": \"Some products are out of stock or not supported.\"\n}","language":"json","status":200,"name":"done - flat products"},{"code":"{\n  \"sites\": {\n    \"5225da1055a0f96c8b000004\": {\n      \"info\": {\n        \"logo\": \"https://core.twotap.com/system/sites/logos/5225/da10/55a0/f96c/8b00/0004/small/5225da1055a0f96c8b000004.png?1467509483762\",\n        \"name\": \"Target\",\n        \"url\": \"target.com\"\n      },\n      \"coupon_support\": true,\n      \"gift_card_support\": true,\n      \"checkout_support\": [\"noauthCheckout\", \"localCheckout\"],\n      \"shipping_countries_support\": [\"United States of America\", \"Japan\"],\n      \"billing_countries_support\": [\"United States of America\", \"Japan\"],\n      \"shipping_options\": {\n        \"cheapest\": \"Default shipping option\"\n      },\n      \"add_to_cart\": {\n        \"e987cc0e00b50b6edb0b785ca0ce3efb\": {\n          \"title\": \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\",\n          \"price\": \"$47.99\",\n          \"original_price\": \"$79.99\",\n          \"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n          \"alt_images\": [\"http://target.scene7.com/is/image/Target/12877464?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt01?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt02?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt03?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt04?wid=800\", \"http://target.scene7.com/is/image/Target/12877464_Alt05?wid=800\"],\n          \"description\": \"Product description\",\n          \"returns\": \"Return policy\",\n          \"categories\": [\"home\", \"dining & entertaining\", \"flatware\", \"flatware sets\", \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\"],\n          \"extra_info\": \"\",\n          \"pickup_support\": true,\n          \"required_field_values\": {\n            \"color\":[\n              {\n                \"value\":\"http://scene7.targetimg.com/is/image/16640462_Swatch\",\n                \"text\":\"Ebony\",\n                \"price\":\"$29.99\",\n                \"image\":\"http://scene7.targetimg.com/is/image/16640462?wid=410&hei=410\",\n                \"extra_info\":\"\",\n                \"dep\":{\n                  \"size\":[\n                    {\n                      \"value\":\"2\",\n                      \"text\":\"2\",\n                      \"price\":\"$29.99\",\n                      \"image\":\"http://scene7.targetimg.com/is/image/16640454?       wid=480&hei=480\",\n                      \"extra_info\":\"\",\n                      \"dep\":{\n                      }\n                    },\n                    {\n                      \"value\":\"4\",\n                      \"text\":\"4\",\n                      \"price\":\"$29.99\",\n                      \"image\":\"http://scene7.targetimg.com/is/image/16640455?wid=480&hei=480\",\n                      \"extra_info\":\"\",\n                      \"dep\":{\n                      }\n                    },\n                  ]\n                },\n              },\n            ],\n          },\n          \"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n          \"discounted_price\": null,\n          \"required_fields\": {\n            \"quantity\": {\n              \"input_type\": \"text\",\n              \"input_name\": \"INPUT\"\n            },\n            \"size\": {\n              \"input_type\": \"select-one\",\n              \"input_name\": \"SELECT\"\n            },\n            \"color\": {\n              \"input_type\": \"select-one\",\n              \"input_name\": \"SELECT\"\n            }\n          },\n          \"status\": \"done\",\n          \"clean_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n          \"original_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\"\n        }\n      },\n      \"failed_to_add_to_cart\": {\n        \"046d87a2152507c2055e0a5a369eb4b9\": {\n          \"original_url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"clean_url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"status\": \"failed\",\n          \"discounted_price\": null,\n          \"original_price\": null,\n          \"price\": null,\n          \"pickup_support\": false,\n          \"image\": \"\",\n          \"url\": \"http://www.target.com/p/out-of-stock-product\",\n          \"raw\": {}\n        }\n      }\n    }\n  },\n  \"user_id\": null,\n  \"unknown_urls\": [],\n  \"cart_id\": \"57786aebdfeb41503dcac297\",\n  \"country\": \"us\",\n  \"stored_field_values\": {},\n  \"message\": \"has_failures\",\n  \"description\": \"Some products are out of stock or not supported.\"\n}","language":"json","status":200,"name":"done - tree products"}]},"settings":"","url":"/cart/status"},"body":"Call '/cart/status' to see the status of an '/cart' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Response description\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"message\",\n    \"0-1\": \"If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.\",\n    \"1-0\": \"description\",\n    \"1-1\": \"A more human-friendly description of the message.\",\n    \"2-0\": \"unknown_urls\",\n    \"2-1\": \"An array with URLs that Two Tap does not support yet.\",\n    \"3-0\": \"sites\",\n    \"3-1\": \"A hash that contains information grouped by a siteID.\",\n    \"4-0\": \"sites[id][info]\",\n    \"4-1\": \"A hash that contains the 'name' and 'url' of the site.\",\n    \"5-0\": \"sites[id][coupon_support]\",\n    \"5-1\": \"true or false. If we have coupon support for a certain site.\",\n    \"6-0\": \"sites[id][gift_card_support]\",\n    \"6-1\": \"true or false. If we have gift card support for a certain site.\",\n    \"7-1\": \"Can be empty, or a hash that contains available shipping options. { \\\"cheapest\\\": \\\"description\\\", \\\"fastest\\\": \\\"description\\\" }.\",\n    \"7-0\": \"sites[id][shipping_options]\",\n    \"8-0\": \"sites[id][checkout_support]\",\n    \"8-1\": \"An array that contains the available checkout types for a site_id. Possible values are \\\"noauthCheckout\\\", \\\"localCheckout\\\", and \\\"authCheckout\\\". See the fields_input examples below.\\n\\nFor guest checkouts send  'noauthCheckout' fields. \\n\\nFor pickup from store checkouts send \\n\\\"localCheckout\\\" and \\\"pickup\\\"\\n\\nFor authenticated checkouts send the \\\"authCheckout\\\" and \\\"login\\\".\",\n    \"9-0\": \"sites[id][shipping_countries_support]\",\n    \"9-1\": \"The countries where this product can be shipped.\",\n    \"10-0\": \"sites[id][billing_countries_support]\",\n    \"10-1\": \"The credit cards from these countries are supported for payment.\",\n    \"12-0\": \"sites[id][add_to_cart]\",\n    \"12-1\": \"A hash that contains product information grouped by it's 'url' MD5.\",\n    \"13-0\": \"sites[id][add_to_cart][productMD5][last_message]\",\n    \"13-1\": \"The latest status message sent by the request processor. This is used during the 'still_processing' phase.\",\n    \"14-0\": \"sites[id][add_to_cart][productMD5][required_fields]\",\n    \"14-1\": \"A hash that contains the product required fields grouped by their field name.\",\n    \"15-0\": \"sites[id][add_to_cart][productMD5][required_field_values]\",\n    \"15-1\": \"Depending on how you set the product_attributes_format request argument, either a hash containing the possible product required field values as a dependency tree, or an array listing each possible product attribute combination.\",\n    \"16-0\": \"sites[id][add_to_cart][productMD5][url]\",\n    \"16-1\": \"URL of the product.\",\n    \"19-0\": \"sites[id][add_to_cart][productMD5][image]\",\n    \"19-1\": \"The product's image URL.\",\n    \"20-0\": \"sites[id][add_to_cart][productMD5][alt_images]\",\n    \"20-1\": \"The product's secondary images as an array.\",\n    \"21-1\": \"The product's price.\",\n    \"21-0\": \"sites[id][add_to_cart][productMD5][price]\",\n    \"27-1\": \"Similar to sites[id][add_to_cart] however it lists which products have failed processing for some reason.\",\n    \"22-0\": \"sites[id][add_to_cart][productMD5][title]\",\n    \"22-1\": \"The product's title.\",\n    \"23-0\": \"sites[id][add_to_cart][productMD5][description]\",\n    \"23-1\": \"The product's description.\",\n    \"25-0\": \"sites[id][add_to_cart][productMD5][returns]\",\n    \"25-1\": \"The product specific return policy.\",\n    \"26-0\": \"sites[id][add_to_cart][productMD5][status]\",\n    \"26-1\": \"The processing status for this product. Can be 'done' or 'still_processing'.\",\n    \"27-0\": \"sites[id][failed_to_add_to_cart]\",\n    \"28-1\": \"\",\n    \"24-0\": \"sites[id][add_to_cart][productMD5][pickup_support]\",\n    \"24-1\": \"If the products supports pickup from store. true or false.\",\n    \"11-0\": \"sites[id][returns]\",\n    \"11-1\": \"The site-wide return policy. There might also be a product specific return policy.\",\n    \"17-0\": \"sites[id][add_to_cart][productMD5][original_url]\",\n    \"17-1\": \"This is the URL you sent to /cart.\\n\\n**Use this to match products from Two Tap's response to what you sent.** \",\n    \"18-0\": \"sites[id][add_to_cart][productMD5][clean_url]\",\n    \"18-1\": \"This is a canonical version of the URL that Two Tap uses internally for caching, feeds, and more.\"\n  },\n  \"cols\": 2,\n  \"rows\": 28\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T18:30:40.276Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":24,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"cart-status","sync_unique":"","title":"/cart/status","type":"get","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

get/cart/status


Query Params

public_token:
required
string
Your Two Tap public token.
cart_id:
required
string
The cart id that is sent by '/cart'.
product_attributes_format:
string
(Optional) If you set this to 'flat' the product attributes will be returned as an array instead of a tree.
test_mode:
string
(Optional) fake_confirm. A way to test the API the interface without making actual purchases.
destination_country:
string
(Optional) If you know most orders are coming from Japan, for instance, you can set this as your default country to receive prices in local currency.
Call '/cart/status' to see the status of an '/cart' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'. [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "message", "0-1": "If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.", "1-0": "description", "1-1": "A more human-friendly description of the message.", "2-0": "unknown_urls", "2-1": "An array with URLs that Two Tap does not support yet.", "3-0": "sites", "3-1": "A hash that contains information grouped by a siteID.", "4-0": "sites[id][info]", "4-1": "A hash that contains the 'name' and 'url' of the site.", "5-0": "sites[id][coupon_support]", "5-1": "true or false. If we have coupon support for a certain site.", "6-0": "sites[id][gift_card_support]", "6-1": "true or false. If we have gift card support for a certain site.", "7-1": "Can be empty, or a hash that contains available shipping options. { \"cheapest\": \"description\", \"fastest\": \"description\" }.", "7-0": "sites[id][shipping_options]", "8-0": "sites[id][checkout_support]", "8-1": "An array that contains the available checkout types for a site_id. Possible values are \"noauthCheckout\", \"localCheckout\", and \"authCheckout\". See the fields_input examples below.\n\nFor guest checkouts send 'noauthCheckout' fields. \n\nFor pickup from store checkouts send \n\"localCheckout\" and \"pickup\"\n\nFor authenticated checkouts send the \"authCheckout\" and \"login\".", "9-0": "sites[id][shipping_countries_support]", "9-1": "The countries where this product can be shipped.", "10-0": "sites[id][billing_countries_support]", "10-1": "The credit cards from these countries are supported for payment.", "12-0": "sites[id][add_to_cart]", "12-1": "A hash that contains product information grouped by it's 'url' MD5.", "13-0": "sites[id][add_to_cart][productMD5][last_message]", "13-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase.", "14-0": "sites[id][add_to_cart][productMD5][required_fields]", "14-1": "A hash that contains the product required fields grouped by their field name.", "15-0": "sites[id][add_to_cart][productMD5][required_field_values]", "15-1": "Depending on how you set the product_attributes_format request argument, either a hash containing the possible product required field values as a dependency tree, or an array listing each possible product attribute combination.", "16-0": "sites[id][add_to_cart][productMD5][url]", "16-1": "URL of the product.", "19-0": "sites[id][add_to_cart][productMD5][image]", "19-1": "The product's image URL.", "20-0": "sites[id][add_to_cart][productMD5][alt_images]", "20-1": "The product's secondary images as an array.", "21-1": "The product's price.", "21-0": "sites[id][add_to_cart][productMD5][price]", "27-1": "Similar to sites[id][add_to_cart] however it lists which products have failed processing for some reason.", "22-0": "sites[id][add_to_cart][productMD5][title]", "22-1": "The product's title.", "23-0": "sites[id][add_to_cart][productMD5][description]", "23-1": "The product's description.", "25-0": "sites[id][add_to_cart][productMD5][returns]", "25-1": "The product specific return policy.", "26-0": "sites[id][add_to_cart][productMD5][status]", "26-1": "The processing status for this product. Can be 'done' or 'still_processing'.", "27-0": "sites[id][failed_to_add_to_cart]", "28-1": "", "24-0": "sites[id][add_to_cart][productMD5][pickup_support]", "24-1": "If the products supports pickup from store. true or false.", "11-0": "sites[id][returns]", "11-1": "The site-wide return policy. There might also be a product specific return policy.", "17-0": "sites[id][add_to_cart][productMD5][original_url]", "17-1": "This is the URL you sent to /cart.\n\n**Use this to match products from Two Tap's response to what you sent.** ", "18-0": "sites[id][add_to_cart][productMD5][clean_url]", "18-1": "This is a canonical version of the URL that Two Tap uses internally for caching, feeds, and more." }, "cols": 2, "rows": 28 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Call '/cart/status' to see the status of an '/cart' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'. [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "message", "0-1": "If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.", "1-0": "description", "1-1": "A more human-friendly description of the message.", "2-0": "unknown_urls", "2-1": "An array with URLs that Two Tap does not support yet.", "3-0": "sites", "3-1": "A hash that contains information grouped by a siteID.", "4-0": "sites[id][info]", "4-1": "A hash that contains the 'name' and 'url' of the site.", "5-0": "sites[id][coupon_support]", "5-1": "true or false. If we have coupon support for a certain site.", "6-0": "sites[id][gift_card_support]", "6-1": "true or false. If we have gift card support for a certain site.", "7-1": "Can be empty, or a hash that contains available shipping options. { \"cheapest\": \"description\", \"fastest\": \"description\" }.", "7-0": "sites[id][shipping_options]", "8-0": "sites[id][checkout_support]", "8-1": "An array that contains the available checkout types for a site_id. Possible values are \"noauthCheckout\", \"localCheckout\", and \"authCheckout\". See the fields_input examples below.\n\nFor guest checkouts send 'noauthCheckout' fields. \n\nFor pickup from store checkouts send \n\"localCheckout\" and \"pickup\"\n\nFor authenticated checkouts send the \"authCheckout\" and \"login\".", "9-0": "sites[id][shipping_countries_support]", "9-1": "The countries where this product can be shipped.", "10-0": "sites[id][billing_countries_support]", "10-1": "The credit cards from these countries are supported for payment.", "12-0": "sites[id][add_to_cart]", "12-1": "A hash that contains product information grouped by it's 'url' MD5.", "13-0": "sites[id][add_to_cart][productMD5][last_message]", "13-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase.", "14-0": "sites[id][add_to_cart][productMD5][required_fields]", "14-1": "A hash that contains the product required fields grouped by their field name.", "15-0": "sites[id][add_to_cart][productMD5][required_field_values]", "15-1": "Depending on how you set the product_attributes_format request argument, either a hash containing the possible product required field values as a dependency tree, or an array listing each possible product attribute combination.", "16-0": "sites[id][add_to_cart][productMD5][url]", "16-1": "URL of the product.", "19-0": "sites[id][add_to_cart][productMD5][image]", "19-1": "The product's image URL.", "20-0": "sites[id][add_to_cart][productMD5][alt_images]", "20-1": "The product's secondary images as an array.", "21-1": "The product's price.", "21-0": "sites[id][add_to_cart][productMD5][price]", "27-1": "Similar to sites[id][add_to_cart] however it lists which products have failed processing for some reason.", "22-0": "sites[id][add_to_cart][productMD5][title]", "22-1": "The product's title.", "23-0": "sites[id][add_to_cart][productMD5][description]", "23-1": "The product's description.", "25-0": "sites[id][add_to_cart][productMD5][returns]", "25-1": "The product specific return policy.", "26-0": "sites[id][add_to_cart][productMD5][status]", "26-1": "The processing status for this product. Can be 'done' or 'still_processing'.", "27-0": "sites[id][failed_to_add_to_cart]", "28-1": "", "24-0": "sites[id][add_to_cart][productMD5][pickup_support]", "24-1": "If the products supports pickup from store. true or false.", "11-0": "sites[id][returns]", "11-1": "The site-wide return policy. There might also be a product specific return policy.", "17-0": "sites[id][add_to_cart][productMD5][original_url]", "17-1": "This is the URL you sent to /cart.\n\n**Use this to match products from Two Tap's response to what you sent.** ", "18-0": "sites[id][add_to_cart][productMD5][clean_url]", "18-1": "This is a canonical version of the URL that Two Tap uses internally for caching, feeds, and more." }, "cols": 2, "rows": 28 } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f843","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\ncart_id = ARGV[0]\nfields_input = { \n  [site_id]: { \n    addToCart: { \n      [product_md5]: { \n        size: 'M'\n      }\n    },\n    noauthCheckout: {\n      shipping_zip: '94303',\n      shipping_city: 'City',\n      shipping_state: 'State'\n    },\n    coupons: [\n      \"coupon_one\",\n      \"coupon_two\"\n    ],\n    shipping_option: 'cheapest'\n  } \n}\n\nproducts = [ 'http://fab.com/sale/4850/product/11263/', 'http://fab.com/sale/4800/product/43565/' ]\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/cart/estimates?public_token=PUBLIC_TOKEN\", { \n  cart_id: cart_id, \n  fields_input: fields_input, \n  products: products \n}\n\nputs response.body","language":"ruby"},{"code":"#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\n\ncurl \"https://api.twotap.com/v1.0/cart/estimates?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '{\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID: {\n      \"addToCart\": {\n        \"PRODUCT_MD5\": {\n          \"size\": \"M\" \n        }\n      },\n      \"noauthCheckout\": {\n        \"shipping_zip\": \"94303\",\n        \"shipping_city\": \"City\",\n        \"shipping_state\": \"State\"\n      },\n      \"shipping_option\": \"cheapest\"\n    }\n  }\n}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\npublic_token = 'PUBLIC_TOKEN'\npayload = {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"addToCart\": {\n        \"PRODUCT_MD5\": {\n          \"size\": \"M\" \n        }\n      },\n      \"noauthCheckout\": {\n        \"shipping_zip\": \"94303\",\n        \"shipping_city\": \"City\",\n        \"shipping_state\": \"State\"\n      },\n      \"shipping_option\": \"cheapest\"\n    }\n  }\n};\nr = requests.post('https://api.twotap.com/v1.0/cart/estimates?public_token=' + public_token,\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\nprint(r.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/cart/estimates?public_token=PUBLIC_TOKEN', {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"addToCart\": {\n        \"PRODUCT_MD5\": {\n          \"size\": \"M\" \n        },\n        \"noauthCheckout\": {\n          \"shipping_zip\": \"94303\",\n          \"shipping_city\": \"City\",\n          \"shipping_state\": \"State\"\n        },\n        \"shipping_option\": \"cheapest\"\n      }\n    }\n  }\n}, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nrequest({\n  url: 'https://api.twotap.com/v1.0/cart/estimates?public_token=' + public_token,\n  json: {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"addToCart\": {\n        \"PRODUCT_MD5\": {\n          \"size\": \"M\" \n        }\n      },\n      \"noauthCheckout\": {\n        \"shipping_zip\": \"94303\",\n        \"shipping_city\": \"City\",\n        \"shipping_state\": \"State\"\n      },\n      \"shipping_option\": \"cheapest\"\n    }\n  }\n},\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\n\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$url = 'https://api.twotap.com/v1.0/cart/estimates?public_token='.$public_token;\n$payload = array(\n  \"cart_id\" => \"CART_ID\",\n  \"fields_input\" => array(\n    \"SITE_ID\" => array(\n      \"addToCart\" => array(\n        \"PRODUCT_MD5\" => array(\n          \"size\" => \"M\"\n        )\n      ),\n      \"noauthCheckout\" => array(\n        \"shipping_zip\" => \"94303\",\n        \"shipping_city\" => \"City\",\n        \"shipping_state\" => \"State\"\n      ),\n      \"shipping_option\" => \"cheapest\"\n    )\n  )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    public_token := \"PUBLIC_TOKEN\"\n    url := \"https://api.twotap.com/v1.0/cart/estimates?public_token=\" + public_token\n    var jsonStr = []byte(`{\n      \"cart_id\": \"CART_ID\",\n      \"fields_input\": {\n        \"SITE_ID\": {\n          \"addToCart\": {\n            \"PRODUCT_MD5\": {\n              \"size\": \"M\" \n            }\n          },\n          \"noauthCheckout\": {\n            \"shipping_zip\": \"94303\",\n            \"shipping_city\": \"City\",\n            \"shipping_state\": \"State\"\n          },\n          \"shipping_option\": \"cheapest\"\n        }\n      }\n    }`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    req.Header.Add(\"Content-Type\", \"application/json\")\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var public_token = \"PUBLIC_TOKEN\";\n      var cart_id = \"CART_ID\";\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/cart/estimates?public_token=\" + public_token);\n      dynamic payload = new ExpandoObject ();\n      payload.cart_id = cart_id;\n      payload.fields_input = new ExpandoObject ();\n      payload.fields_input.SITE_ID = new ExpandoObject ();\n      payload.fields_input.SITE_ID.addToCart = new ExpandoObject ();\n      payload.fields_input.SITE_ID.addToCart.PRODUCT_MD5 = new ExpandoObject ();\n      payload.fields_input.SITE_ID.addToCart.PRODUCT_MD5.size = \"M\";\n      payload.fields_input.SITE_ID.noauthCheckout = new ExpandoObject ();\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_zip = \"94303\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_city = \"City\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_state = \"State\";\n      payload.fields_input.shipping_option = \"cheapest\";\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"params":[{"_id":"55a30cf4ef69351700664e68","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"55a2a251a50aca1700782e9a","ref":"","required":true,"desc":"A cart id that has finished running.","default":"","type":"string","name":"cart_id","in":"body"},{"_id":"55a2a251a50aca1700782e99","ref":"","required":false,"desc":"A hash containing purchase information by site_id.","default":"","type":"object","name":"fields_input","in":"body"},{"_id":"55a2a251a50aca1700782e98","ref":"","required":false,"desc":"*(Optional)* An array of product URLs that have accepted by the user. This is useful in case a user removes some items between /cart and /purchase.  If specified fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's that you originally sent us.","default":"","type":"array_string","name":"products","in":"body"},{"_id":"577811732878f70e00495e9b","ref":"","required":false,"desc":"(Optional) If the customer hasn't entered their full information yet you can set up a default country to get landed cost for.","default":"","type":"string","name":"destination_country","in":"body"}],"results":{"codes":[{"status":200,"language":"json","code":"{\n  \"message\": \"done\",\n  \"estimates\": { \n    \"53fb0d1fce04fa71f5000003\": {\n      \"prices\": {\n        \"shipping_price\": \"$8.00\",\n        \"subtotal\": \"$50.00\",\n        \"sales_tax\": \"$6.09\",\n        \"final_price\": \"$64.09\"\n      },\n      \"coupons\": {},\n      \"delivery_days\": {\n        \"min\": 1,\n        \"max\": 5\n      }\n    }\n  },\n  \"estimated_total_prices\": {\n    \"shipping_price\": \"$8.00\",\n    \"subtotal\": \"$50.00\",\n    \"sales_tax\": \"$6.09\",\n    \"final_price\": \"$64.09\"\n  },\n  \"estimated_delivery_days\": {\n    \"min\": 1,\n    \"max\": 5\n  },\n  \"coupons\": {\n    \"53fb0d1fce04fa71f5000003\": {}\n  },\n  \"destination\": \"domestic\"\n}","name":"OK - Domestic"},{"code":"\n{\n  \"message\":\"done\",\n  \"estimates\":{\n    \"51bf1d1055a0f9e0d0000003\":{\n      \"prices\":{\n        \"shipping_price\":\"$5.00\",\n        \"sales_tax\":\"$2.54\",\n        \"coupon_value\": \"$3.00\",\n        \"final_price\":\"$31.54\"\n      },\n\t\t\t\"coupons\":{\n\t\t\t\t\"coupon_one\":{\n\t\t\t\t\t\"label\":\"30% off any one item.\",\n\t\t\t\t\t\"status\":\"valid\"\n\t\t\t\t},\n\t\t\t\t\"coupon_two\":{\n\t\t\t\t\t\"label\":\"Invalid: $10 off any purchase\",\n\t\t\t\t\t\"status\":\"invalid\"\n\t\t\t\t}\n\t\t\t}\n    }\n  },\n  \"estimated_total_prices\": {\n    \"shipping_price\": \"$5.00\",\n    \"sales_tax\": \"$2.54\",\n    \"coupon_value\": \"$3.00\",\n    \"final_price\": \"$31.54\"\n  },\n}","language":"json","status":200,"name":"OK - Domestic with Coupon"},{"status":200,"name":"OK - INTL","language":"json","code":"{\n\t\"message\": \"done\",\n\t\"estimates\": null,\n\t\"estimated_total_prices\": {\n\t\t\"shipping_price\": \"2263.60 JPY\",\n\t\t\"subtotal\": \"5125.90 JPY\",\n\t\t\"sales_tax\": \"410.07 JPY\",\n\t\t\"final_price\": \"8055.86 JPY\",\n\t\t\"duties\": \"256.29 JPY\"\n\t},\n\t\"estimated_delivery_days\": {\n\t\t\"min\": 1,\n\t\t\"max\": 5\n\t},\n\t\"coupons\": {\n\t\t\"53fb0d1fce04fa71f5000003\": {}\n\t},\n\t\"destination\": \"intl\"\n}"}]},"settings":"","url":"/cart/estimates"},"body":"This endpoint will return an estimated sales tax, shipping price, and final price for a certain cart.\n\nThe more information you can give it the more accurate it becomes.\n\n * Send the shopper selected product options. Some product attribute combinations have different prices so in order to have a valid estimates the attributes are recommended.\n * Send the shoppers shipping city, state, and zip code accurate sales tax calculations.\n\nDomestic orders will contain a breakdown of prices per site, the 'estimates' variable.\n\nInternational orders will only contain the aggregate, the 'estimated_total_prices' variable.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'fields' parameter\"\n}\n[/block]\nThe 'fields' parameter is a hash that looks like below:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"[site_id]\\\":\\n    {\\n      \\\"noauthCheckout\\\": { required checkout fields },\\n      \\\"addToCart\\\": {\\n        \\\"[productMD5_1]\\\": \\\"required product fields\\\",\\n        \\\"[productMD5_2]\\\": \\\"required product fields\\\",\\n\\t    \\\"coupons\\\": [\\n      \\t\\\"coupon_one\\\",\\n     \\t\\t\\\"coupon_two\\\"\\n\\t\\t  ],\\n      \\\"shipping_option\\\": { \\\"cheapest or fastest\\\" } (optional),\\n    }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Response description\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"message\",\n    \"0-1\": \"If Two Tap has completed the request: 'done'.\",\n    \"1-0\": \"estimates\",\n    \"1-1\": \"A hash that contains price and coupon information broken down by site_id. \\n\\n**Only available for domestic purchases.**\",\n    \"2-0\": \"estimates[site_id][prices]\",\n    \"2-1\": \"A hash that can contain: 'subtotal', 'coupon_value', 'shipping_price', 'sales_tax', 'final_price'.\\n\\n**Only available for domestic purchases.**\",\n    \"4-0\": \"estimates[site_id][coupons]\",\n    \"4-1\": \"A hash keyed by coupon values.\\n\\n**Only available for domestic purchases.**\",\n    \"5-0\": \"estimates[site_id][coupons][coupon_code][status]\",\n    \"5-1\": \"The status which can be 'invalid', 'valid', or 'unknown'.\\n\\n**Only available for domestic purchases.**\",\n    \"6-0\": \"estimates[site_id][coupons][coupon_code][label]\",\n    \"6-1\": \"A short label about the coupon, eg. \\\"10% of any one product\\\". Present if status is 'valid' or 'invalid'.\\n\\n**Only available for domestic purchases.**\",\n    \"3-0\": \"estimates[site_id][prices][coupon_value]\",\n    \"3-1\": \"If the coupon statuses are 'valid' this will be an amount. \\n\\nOtherwise, it will be a text that says: 'applied at checkout'.\\n\\n**Only available for domestic purchases.**\",\n    \"7-0\": \"estimated_total_prices\",\n    \"7-1\": \"A hash that contains price and coupon information for the whole cart.\\n\\nCan contain: 'subtotal', 'coupon_value', 'discount_value', 'shipping_price', 'sales_tax', 'duties', 'final_price'.\\n\\n**Available for both domestic and international purchases.**\",\n    \"8-0\": \"estimated_delivery_days\",\n    \"8-1\": \"An estimated delivery time for the cart in day.\\n\\nLooks like: \\n{ \\\"min\\\": 1, \\\"max\\\": 5 }\",\n    \"9-0\": \"destination\",\n    \"9-1\": \"'domestic' or 'intl'.\"\n  },\n  \"cols\": 2,\n  \"rows\": 10\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T19:12:34.552Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":25,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"cart-estimates","sync_unique":"","title":"/cart/estimates","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/cart/estimates


Body JSON

public_token:
required
string
Your Two Tap public token.
cart_id:
required
string
A cart id that has finished running.
fields_input:
object
A hash containing purchase information by site_id.
products:
array of strings
*(Optional)* An array of product URLs that have accepted by the user. This is useful in case a user removes some items between /cart and /purchase. If specified fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's that you originally sent us.
destination_country:
string
(Optional) If the customer hasn't entered their full information yet you can set up a default country to get landed cost for.
This endpoint will return an estimated sales tax, shipping price, and final price for a certain cart. The more information you can give it the more accurate it becomes. * Send the shopper selected product options. Some product attribute combinations have different prices so in order to have a valid estimates the attributes are recommended. * Send the shoppers shipping city, state, and zip code accurate sales tax calculations. Domestic orders will contain a breakdown of prices per site, the 'estimates' variable. International orders will only contain the aggregate, the 'estimated_total_prices' variable. [block:api-header] { "type": "basic", "title": "The 'fields' parameter" } [/block] The 'fields' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"[site_id]\":\n {\n \"noauthCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n\t \"coupons\": [\n \t\"coupon_one\",\n \t\t\"coupon_two\"\n\t\t ],\n \"shipping_option\": { \"cheapest or fastest\" } (optional),\n }\n}", "language": "javascript" } ] } [/block] [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "message", "0-1": "If Two Tap has completed the request: 'done'.", "1-0": "estimates", "1-1": "A hash that contains price and coupon information broken down by site_id. \n\n**Only available for domestic purchases.**", "2-0": "estimates[site_id][prices]", "2-1": "A hash that can contain: 'subtotal', 'coupon_value', 'shipping_price', 'sales_tax', 'final_price'.\n\n**Only available for domestic purchases.**", "4-0": "estimates[site_id][coupons]", "4-1": "A hash keyed by coupon values.\n\n**Only available for domestic purchases.**", "5-0": "estimates[site_id][coupons][coupon_code][status]", "5-1": "The status which can be 'invalid', 'valid', or 'unknown'.\n\n**Only available for domestic purchases.**", "6-0": "estimates[site_id][coupons][coupon_code][label]", "6-1": "A short label about the coupon, eg. \"10% of any one product\". Present if status is 'valid' or 'invalid'.\n\n**Only available for domestic purchases.**", "3-0": "estimates[site_id][prices][coupon_value]", "3-1": "If the coupon statuses are 'valid' this will be an amount. \n\nOtherwise, it will be a text that says: 'applied at checkout'.\n\n**Only available for domestic purchases.**", "7-0": "estimated_total_prices", "7-1": "A hash that contains price and coupon information for the whole cart.\n\nCan contain: 'subtotal', 'coupon_value', 'discount_value', 'shipping_price', 'sales_tax', 'duties', 'final_price'.\n\n**Available for both domestic and international purchases.**", "8-0": "estimated_delivery_days", "8-1": "An estimated delivery time for the cart in day.\n\nLooks like: \n{ \"min\": 1, \"max\": 5 }", "9-0": "destination", "9-1": "'domestic' or 'intl'." }, "cols": 2, "rows": 10 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



This endpoint will return an estimated sales tax, shipping price, and final price for a certain cart. The more information you can give it the more accurate it becomes. * Send the shopper selected product options. Some product attribute combinations have different prices so in order to have a valid estimates the attributes are recommended. * Send the shoppers shipping city, state, and zip code accurate sales tax calculations. Domestic orders will contain a breakdown of prices per site, the 'estimates' variable. International orders will only contain the aggregate, the 'estimated_total_prices' variable. [block:api-header] { "type": "basic", "title": "The 'fields' parameter" } [/block] The 'fields' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"[site_id]\":\n {\n \"noauthCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n\t \"coupons\": [\n \t\"coupon_one\",\n \t\t\"coupon_two\"\n\t\t ],\n \"shipping_option\": { \"cheapest or fastest\" } (optional),\n }\n}", "language": "javascript" } ] } [/block] [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "message", "0-1": "If Two Tap has completed the request: 'done'.", "1-0": "estimates", "1-1": "A hash that contains price and coupon information broken down by site_id. \n\n**Only available for domestic purchases.**", "2-0": "estimates[site_id][prices]", "2-1": "A hash that can contain: 'subtotal', 'coupon_value', 'shipping_price', 'sales_tax', 'final_price'.\n\n**Only available for domestic purchases.**", "4-0": "estimates[site_id][coupons]", "4-1": "A hash keyed by coupon values.\n\n**Only available for domestic purchases.**", "5-0": "estimates[site_id][coupons][coupon_code][status]", "5-1": "The status which can be 'invalid', 'valid', or 'unknown'.\n\n**Only available for domestic purchases.**", "6-0": "estimates[site_id][coupons][coupon_code][label]", "6-1": "A short label about the coupon, eg. \"10% of any one product\". Present if status is 'valid' or 'invalid'.\n\n**Only available for domestic purchases.**", "3-0": "estimates[site_id][prices][coupon_value]", "3-1": "If the coupon statuses are 'valid' this will be an amount. \n\nOtherwise, it will be a text that says: 'applied at checkout'.\n\n**Only available for domestic purchases.**", "7-0": "estimated_total_prices", "7-1": "A hash that contains price and coupon information for the whole cart.\n\nCan contain: 'subtotal', 'coupon_value', 'discount_value', 'shipping_price', 'sales_tax', 'duties', 'final_price'.\n\n**Available for both domestic and international purchases.**", "8-0": "estimated_delivery_days", "8-1": "An estimated delivery time for the cart in day.\n\nLooks like: \n{ \"min\": 1, \"max\": 5 }", "9-0": "destination", "9-1": "'domestic' or 'intl'." }, "cols": 2, "rows": 10 } [/block]
{"__v":1,"_id":"57780374ea758f0e00e6f844","api":{"auth":"required","examples":{"codes":[{"name":"","code":"\n#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\ncart_id = ARGV[0]\n\nfields_input = { \n  [site_id]: {\n    \"noauthCheckout\": { \"email\" => \"shopper@gmail.com\", \"shipping_telephone\" => \"6503941234\", \"shipping_zip\" => \"94303\", \"shipping_state\" => \"California\", \"shipping_city\" => \"Palo Alto\", \"shipping_address\" => \"555 Palo Alto Avenue\", \"..\" => \"..\" },\n    \"addToCart\": {\n      [product_md5]: { \"quantity\": 1 }\n    }\n  }\n}\n\naffiliate_links = {\n  [site_id]: \"http://affiliate_link\"  \n}\n\nproducts = [ 'http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605' ]\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN\", { \n  cart_id: cart_id, \n  fields_input: fields_input, \n  affiliate_links: affiliate_links, \n  products: products \n}\n\nputs response.body","language":"ruby"},{"code":"\n#!/bin/sh\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\n\ncurl \"https://api.twotap.com/v1.0/purchase?public_token=$PUBLIC_TOKEN\" --header \"Content-Type: application/json\" --data-binary '\n{\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\": {\n        \"[product_md5]\": { \"quantity\": 1 }\n      }\n    }\n  },\n  \"affiliate_links\": {\n   \"SITE_ID\": \"http://affiliate_link\"  \n  },\n  \"products\": [ \"http://fab.com/sale/4850/product/11263\" ]\n}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\npublic_token = 'PUBLIC_TOKEN'\npayload = {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\": {\n        \"[product_md5]\": { \"quantity\": 1 }\n      }\n    }\n  },\n  \"affiliate_links\": {\n   \"SITE_ID\": \"http://affiliate_link\"  \n  },\n  \"products\": [ \"http://fab.com/sale/4850/product/11263\" ]\n};\nr = requests.post('https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\nprint(r.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/purchase?public_token=PUBLIC_TOKEN', {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\": {\n        \"[product_md5]\": { \"quantity\": 1 }\n      }\n    }\n  },\n  \"affiliate_links\": {\n   \"SITE_ID\": \"http://affiliate_link\"  \n  },\n  \"products\": [ \"http://fab.com/sale/4850/product/11263\" ]\n}, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nrequest({\n  url: 'https://api.twotap.com/v1.0/purchase?public_token=' + public_token,\n  json: {\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\": {\n        \"[product_md5]\": { \"quantity\": 1 }\n      }\n    }\n  },\n  \"affiliate_links\": {\n  \"SITE_ID\": \"http://affiliate_link\"  \n  },\n  \"products\": [ \"http://fab.com/sale/4850/product/11263\" ]\n},\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$url = 'https://api.twotap.com/v1.0/purchase?public_token='.$public_token;\n$payload = array(\n  \"cart_id\" => \"CART_ID\",\n  \"fields_input\" => array(\n    \"SITE_ID\" => array(\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\" => array(\n        \"[product_md5]\" => array( \"quantity\" => 1 )\n      )\n    )\n  ),\n  \"affiliate_links\" => array(\n   \"SITE_ID\" => \"http://affiliate_link\"  \n  ),\n  \"products\" => array(\n    \"http://fab.com/sale/4850/product/11263\"\n  ),\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    public_token := \"PUBLIC_TOKEN\"\n    url := \"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token\n    var jsonStr = []byte(`{\n  \"cart_id\": \"CART_ID\",\n  \"fields_input\": {\n    \"SITE_ID\": {\n      \"noauthCheckout\": { \"email\": \"shopper@gmail.com\", \"shipping_telephone\": \"6503941234\", \"shipping_zip\": \"94303\", \"shipping_state\": \"California\", \"shipping_city\": \"Palo Alto\", \"shipping_address\": \"555 Palo Alto Avenue\", \"..\": \"..\" },\n      \"addToCart\": {\n        \"[product_md5]\": { \"quantity\": 1 }\n      }\n    }\n  },\n  \"affiliate_links\": {\n  \"SITE_ID\": \"http://affiliate_link\"  \n  },\n  \"products\": [ \"http://fab.com/sale/4850/product/11263\" ]\n}`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    req.Header.Add(\"Content-Type\", \"application/json\")\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var public_token = \"PUBLIC_TOKEN\";\n      var cart_id = \"CART_ID\";\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase?public_token=\" + public_token);\n      dynamic payload = new ExpandoObject ();\n      payload.cart_id = cart_id;\n      payload.fields_input = new ExpandoObject ();\n      payload.fields_input.SITE_ID = new ExpandoObject ();\n      payload.fields_input.SITE_ID.noauthCheckout = new ExpandoObject ();\n      payload.fields_input.SITE_ID.noauthCheckout.email = \"shopper@gmail.com\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_telephone = \"6503941234\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_zip = \"94303\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_city = \"Palo Alto\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_state = \"California\";\n      payload.fields_input.SITE_ID.noauthCheckout.shipping_address = \"555 Palo Alto Avenue\";\n      payload.fields_input.SITE_ID.addToCart = new ExpandoObject ();\n      payload.fields_input.SITE_ID.addToCart.PRODUCT_MD5 = new ExpandoObject ();\n      payload.fields_input.SITE_ID.addToCart.PRODUCT_MD5.quantity = 1;\n      payload.affiliate_links = new ExpandoObject ();\n      payload.affiliate_links.SITE_ID = \"http://affiliate_link\";\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"params":[{"_id":"55a30d0489d84c0d002af0ae","ref":"","in":"body","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token"},{"_id":"55a2a5b3cfd73f2100f19752","ref":"","in":"body","required":true,"desc":"The cart id that is sent by '/cart'.","default":"","type":"string","name":"cart_id"},{"_id":"55a2a5b3cfd73f2100f19751","ref":"","in":"body","required":true,"desc":"A hash containing purchase information by site_id.","default":"","type":"object","name":"fields_input"},{"_id":"55a2a5b3cfd73f2100f19750","ref":"","in":"body","required":false,"desc":"(Optional) A hash containing affiliate links by site_id.","default":"","type":"object","name":"affiliate_links"},{"_id":"55a2a5b3cfd73f2100f1974f","ref":"","in":"body","required":false,"desc":"(Optional but highly recommended) Instead of polling /purchase/status Two Tap can send callbacks as it's processing the purchase.","default":"","type":"object","name":"confirm"},{"_id":"55a2a5b3cfd73f2100f1974e","default":"","desc":"(Optional) An array of product URLs that have been accepted by the user. This is useful in case an user removes some items between /cart and /purchase. If specified, fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's you originally sent us.","in":"body","name":"products","ref":"","required":false,"type":"array_string"},{"_id":"560da145af9723190093818a","ref":"","in":"body","required":false,"desc":"(Optional) You can send any information here and it will be attached to the purchase and piped back with /status responses and callbacks.","default":"","type":"object","name":"notes"},{"_id":"55a2a5b3cfd73f2100f1974d","ref":"","in":"body","required":false,"desc":"(Optional) fake_confirm. A way to test the API the interface without making actual purchases.","default":"","type":"string","name":"test_mode"},{"_id":"57c22293b4d94e0e007411f3","default":"en","desc":"(Optional) For INTL orders Two Tap sends status update emails to consumers. Set a language for the emails here. ISO 639-1.","in":"body","name":"locale","ref":"","required":false,"type":"string"}],"results":{"codes":[{"name":"","code":"{\n  \"purchase_id\": \"50f414b9e6a4869bf6000010\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\"\n}","language":"json","status":200}]},"settings":"","url":"/purchase"},"body":"Purchase will retrieve the shipping price, sales tax, and final price of the order. It will start the checkout process but not finish it to ensure the data sent back is valid.\n\nTwo Tap can support three checkout types: noauthCheckout (guest checkout), localCheckout (pickup from store), and authCheckout (with a store account, not recommended). You can find what checkouts types the store has enabled by looking in /cart/status at the \"checkout_support\" attribute  for each site_id.\n\nThis request is processed in the background which means you either have to call '/purchase/status' or use the SMS API flow or HTTP API flow to receive callbacks.\n\n**Once this request finishes you will have 5 minutes available to call '/purchase/confirm' to confirm it.**\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"When implementing Two Tap take the asynchronous approach to placing orders and avoid polling /purchase/status. Request all the necessary information, start a /purchase, display a message to the shopper saying \\\"Your order is being placed, you'll receive a confirmation shortly\\\", and let her leave the experience. \\n\\nTwo Tap will send the order in the background and via the SMS API flow or HTTP API flow will call your endpoints at different steps in the process.\\n\\nThis is very similar to the Amazon approach where your order information is accepted instantly and if it wasn't valid you receive an email five minutes later.\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"\",\n  \"body\": \"If you are using the API directly we **highly recommend** you use an address validator like [lob.com ](https://lob.com/)or [easypost.com](https://www.easypost.com/) in your app/service. It's free.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'fields_input' parameter\"\n}\n[/block]\nThe 'fields_input' parameter is a hash that looks like below:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"[site_id]\\\":\\n    {\\n      \\\"noauthCheckout\\\": { required checkout fields },\\n      \\\"addToCart\\\": {\\n        \\\"[productMD5_1]\\\": \\\"required product fields\\\",\\n        \\\"[productMD5_2]\\\": \\\"required product fields\\\",\\n      },\\n      \\\"coupons\\\": [ \\\"coupon value 1\\\", \\\"coupon value 2\\\" ], // (optional)\\n      \\\"gift_cards\\\": [ { \\\"number\\\": \\\"number\\\", \\\"pin\\\": \\\"pin\\\" } ], // (optional)\\n      \\\"shipping_option\\\": { \\\"cheapest or fastest\\\" }, // (optional)\\n    },\\n  \\\"[site_id_2]\\\": { .. }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"noauthCheckout (Guest)\"\n    },\n    {\n      \"code\": \"{\\n  \\\"[site_id]\\\":\\n    {\\n      \\\"authCheckout\\\": { required checkout fields },\\n      \\\"login\\\": { \\\"username\\\": \\\"store account username or email\\\", \\\"password\\\": \\\"store account password\\\" },\\n      \\\"addToCart\\\": {\\n        \\\"[productMD5_1]\\\": \\\"required product fields\\\",\\n        \\\"[productMD5_2]\\\": \\\"required product fields\\\",\\n      },\\n      \\\"coupon\\\": \\\"coupon value\\\", // optional\\n      \\\"gift_card\\\": { \\\"number\\\": \\\"number\\\", \\\"pin\\\": \\\"pin\\\") }, // optional\\n      \\\"shipping_option\\\": { \\\"cheapest or fastest\\\" }, // optional\\n    },\\n  \\\"[site_id_2]\\\": { .. }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"authCheckout (Store account)\"\n    },\n    {\n      \"code\": \"{\\n  \\\"[site_id]\\\":\\n    {\\n      \\\"localCheckout\\\": { required checkout fields },\\n      \\\"addToCart\\\": {\\n        \\\"[productMD5_1]\\\": \\\"required product fields\\\",\\n        \\\"[productMD5_2]\\\": \\\"required product fields\\\",\\n      },\\n      \\\"pickup\\\": {\\n        \\\"[productMD5_1]\\\": \\\"Mountain View\\\",\\n        \\\"[productMD5_2]\\\": \\\"Mountain View\\\",\\n      },\\n      \\\"coupon\\\": \\\"coupon value\\\", // optional\\n      \\\"gift_card\\\": { \\\"number\\\": \\\"number\\\", \\\"pin\\\": \\\"pin\\\") }, // optional\\n    },\\n  \\\"[site_id_2]\\\": { .. }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"localCheckout (Pickup from store)\"\n    }\n  ]\n}\n[/block]\nTo keep things simple if you're building your own native checkout always ask for the following fields, and send them all with each site_id.\n\nThe possible keys and values are listed [here](http://docs.twotap.com/docs/possible-keys-and-values).\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" [ \\n    'email',\\n    'shipping_first_name',\\n    'shipping_last_name',\\n    'shipping_address',\\n    'shipping_city',\\n    'shipping_state',\\n    'shipping_country',\\n    'shipping_zip',\\n    'shipping_telephone',\\n    'billing_first_name',\\n    'billing_last_name',\\n    'billing_address',\\n    'billing_city',\\n    'billing_state',\\n    'billing_country',\\n    'billing_zip',\\n    'billing_telephone',\\n    'card_type',\\n    'card_number',\\n    'card_name',\\n    'expiry_date_year',\\n    'expiry_date_month',\\n    'cvv'\\n  ]\",\n      \"language\": \"json\",\n      \"name\": \"noauthCheckout (Guest) and authCheckout (Store account)\"\n    },\n    {\n      \"code\": \" [ \\n    'email',\\n    'shipping_first_name', // this is the designated pickup person.\\n    'shipping_last_name',\\n    'shipping_zip', // this is the zip for the pickup store.\\n    'billing_first_name',\\n    'billing_last_name',\\n    'billing_address',\\n    'billing_city',\\n    'billing_state',\\n    'billing_country',\\n    'billing_zip',\\n    'billing_telephone',\\n    'card_type',\\n    'card_number',\\n    'card_name',\\n    'expiry_date_year',\\n    'expiry_date_month',\\n    'cvv'\\n  ]\",\n      \"language\": \"json\",\n      \"name\": \"localCheckout (Pickup from store)\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Addresses\",\n  \"body\": \"Due to the way most retailers handle validations (which is turn a factor of the carriers) the only characters allowed for addresses are alphanumerical, comma, dot, space, and /. You can use /fields_input_validate to check your information ahead of time.\\n\\nTo break an address into address_line_1 and address_line_2 add one comma, eg:\\n\\\"106 Shotwell St, Unit 41\\\"\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'affiliate_links' parameter\"\n}\n[/block]\nThe 'affiliate_links' parameter is a hash that looks like below:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{ \\n  \\\"[site_id]\\\": \\\"affiliate_link\\\" \\n}\",\n      \"language\": \"json\",\n      \"name\": \"One affiliate link per site\"\n    },\n    {\n      \"code\": \"{ \\n  \\\"[site_id]\\\": { \\n    \\\"[productMD5]\\\": \\\"affiliate_link\\\" \\n  } \\n}\",\n      \"language\": \"json\",\n      \"name\": \"One affiliate link per product\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'confirm' parameter\"\n}\n[/block]\nInstead of polling /purchase/status Two Tap can send callbacks as it's processing the purchase. See the [SMS API](https://old.twotap.com/docs/#api_sms_flow) flow or [HTTP API](https://old.twotap.com/docs/#api_http_flow) flow.\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" { \\n   method: 'http', \\n   http_confirm_url: 'https://your_confirm_endpoint', \\n   http_update_url: 'https://your_update_endpoint',\\n   skip_confirm: '(optional and dangerous) YOUR_PRIVATE_TOKEN'\\n }\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T19:25:49.871Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":26,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"purchase","sync_unique":"","title":"/purchase","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/purchase


Body JSON

public_token:
required
string
Your Two Tap public token.
cart_id:
required
string
The cart id that is sent by '/cart'.
fields_input:
required
object
A hash containing purchase information by site_id.
affiliate_links:
object
(Optional) A hash containing affiliate links by site_id.
confirm:
object
(Optional but highly recommended) Instead of polling /purchase/status Two Tap can send callbacks as it's processing the purchase.
products:
array of strings
(Optional) An array of product URLs that have been accepted by the user. This is useful in case an user removes some items between /cart and /purchase. If specified, fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's you originally sent us.
notes:
object
(Optional) You can send any information here and it will be attached to the purchase and piped back with /status responses and callbacks.
test_mode:
string
(Optional) fake_confirm. A way to test the API the interface without making actual purchases.
locale:
stringen
(Optional) For INTL orders Two Tap sends status update emails to consumers. Set a language for the emails here. ISO 639-1.
Purchase will retrieve the shipping price, sales tax, and final price of the order. It will start the checkout process but not finish it to ensure the data sent back is valid. Two Tap can support three checkout types: noauthCheckout (guest checkout), localCheckout (pickup from store), and authCheckout (with a store account, not recommended). You can find what checkouts types the store has enabled by looking in /cart/status at the "checkout_support" attribute for each site_id. This request is processed in the background which means you either have to call '/purchase/status' or use the SMS API flow or HTTP API flow to receive callbacks. **Once this request finishes you will have 5 minutes available to call '/purchase/confirm' to confirm it.** [block:callout] { "type": "danger", "body": "When implementing Two Tap take the asynchronous approach to placing orders and avoid polling /purchase/status. Request all the necessary information, start a /purchase, display a message to the shopper saying \"Your order is being placed, you'll receive a confirmation shortly\", and let her leave the experience. \n\nTwo Tap will send the order in the background and via the SMS API flow or HTTP API flow will call your endpoints at different steps in the process.\n\nThis is very similar to the Amazon approach where your order information is accepted instantly and if it wasn't valid you receive an email five minutes later." } [/block] [block:callout] { "type": "warning", "title": "", "body": "If you are using the API directly we **highly recommend** you use an address validator like [lob.com ](https://lob.com/)or [easypost.com](https://www.easypost.com/) in your app/service. It's free." } [/block] [block:api-header] { "type": "basic", "title": "The 'fields_input' parameter" } [/block] The 'fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"[site_id]\":\n {\n \"noauthCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"coupons\": [ \"coupon value 1\", \"coupon value 2\" ], // (optional)\n \"gift_cards\": [ { \"number\": \"number\", \"pin\": \"pin\" } ], // (optional)\n \"shipping_option\": { \"cheapest or fastest\" }, // (optional)\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "noauthCheckout (Guest)" }, { "code": "{\n \"[site_id]\":\n {\n \"authCheckout\": { required checkout fields },\n \"login\": { \"username\": \"store account username or email\", \"password\": \"store account password\" },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"coupon\": \"coupon value\", // optional\n \"gift_card\": { \"number\": \"number\", \"pin\": \"pin\") }, // optional\n \"shipping_option\": { \"cheapest or fastest\" }, // optional\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "authCheckout (Store account)" }, { "code": "{\n \"[site_id]\":\n {\n \"localCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"pickup\": {\n \"[productMD5_1]\": \"Mountain View\",\n \"[productMD5_2]\": \"Mountain View\",\n },\n \"coupon\": \"coupon value\", // optional\n \"gift_card\": { \"number\": \"number\", \"pin\": \"pin\") }, // optional\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "localCheckout (Pickup from store)" } ] } [/block] To keep things simple if you're building your own native checkout always ask for the following fields, and send them all with each site_id. The possible keys and values are listed [here](http://docs.twotap.com/docs/possible-keys-and-values). [block:code] { "codes": [ { "code": " [ \n 'email',\n 'shipping_first_name',\n 'shipping_last_name',\n 'shipping_address',\n 'shipping_city',\n 'shipping_state',\n 'shipping_country',\n 'shipping_zip',\n 'shipping_telephone',\n 'billing_first_name',\n 'billing_last_name',\n 'billing_address',\n 'billing_city',\n 'billing_state',\n 'billing_country',\n 'billing_zip',\n 'billing_telephone',\n 'card_type',\n 'card_number',\n 'card_name',\n 'expiry_date_year',\n 'expiry_date_month',\n 'cvv'\n ]", "language": "json", "name": "noauthCheckout (Guest) and authCheckout (Store account)" }, { "code": " [ \n 'email',\n 'shipping_first_name', // this is the designated pickup person.\n 'shipping_last_name',\n 'shipping_zip', // this is the zip for the pickup store.\n 'billing_first_name',\n 'billing_last_name',\n 'billing_address',\n 'billing_city',\n 'billing_state',\n 'billing_country',\n 'billing_zip',\n 'billing_telephone',\n 'card_type',\n 'card_number',\n 'card_name',\n 'expiry_date_year',\n 'expiry_date_month',\n 'cvv'\n ]", "language": "json", "name": "localCheckout (Pickup from store)" } ] } [/block] [block:callout] { "type": "info", "title": "Addresses", "body": "Due to the way most retailers handle validations (which is turn a factor of the carriers) the only characters allowed for addresses are alphanumerical, comma, dot, space, and /. You can use /fields_input_validate to check your information ahead of time.\n\nTo break an address into address_line_1 and address_line_2 add one comma, eg:\n\"106 Shotwell St, Unit 41\"" } [/block] [block:api-header] { "type": "basic", "title": "The 'affiliate_links' parameter" } [/block] The 'affiliate_links' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{ \n \"[site_id]\": \"affiliate_link\" \n}", "language": "json", "name": "One affiliate link per site" }, { "code": "{ \n \"[site_id]\": { \n \"[productMD5]\": \"affiliate_link\" \n } \n}", "language": "json", "name": "One affiliate link per product" } ] } [/block] [block:api-header] { "type": "basic", "title": "The 'confirm' parameter" } [/block] Instead of polling /purchase/status Two Tap can send callbacks as it's processing the purchase. See the [SMS API](https://old.twotap.com/docs/#api_sms_flow) flow or [HTTP API](https://old.twotap.com/docs/#api_http_flow) flow. [block:code] { "codes": [ { "code": " { \n method: 'http', \n http_confirm_url: 'https://your_confirm_endpoint', \n http_update_url: 'https://your_update_endpoint',\n skip_confirm: '(optional and dangerous) YOUR_PRIVATE_TOKEN'\n }", "language": "json" } ] } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Purchase will retrieve the shipping price, sales tax, and final price of the order. It will start the checkout process but not finish it to ensure the data sent back is valid. Two Tap can support three checkout types: noauthCheckout (guest checkout), localCheckout (pickup from store), and authCheckout (with a store account, not recommended). You can find what checkouts types the store has enabled by looking in /cart/status at the "checkout_support" attribute for each site_id. This request is processed in the background which means you either have to call '/purchase/status' or use the SMS API flow or HTTP API flow to receive callbacks. **Once this request finishes you will have 5 minutes available to call '/purchase/confirm' to confirm it.** [block:callout] { "type": "danger", "body": "When implementing Two Tap take the asynchronous approach to placing orders and avoid polling /purchase/status. Request all the necessary information, start a /purchase, display a message to the shopper saying \"Your order is being placed, you'll receive a confirmation shortly\", and let her leave the experience. \n\nTwo Tap will send the order in the background and via the SMS API flow or HTTP API flow will call your endpoints at different steps in the process.\n\nThis is very similar to the Amazon approach where your order information is accepted instantly and if it wasn't valid you receive an email five minutes later." } [/block] [block:callout] { "type": "warning", "title": "", "body": "If you are using the API directly we **highly recommend** you use an address validator like [lob.com ](https://lob.com/)or [easypost.com](https://www.easypost.com/) in your app/service. It's free." } [/block] [block:api-header] { "type": "basic", "title": "The 'fields_input' parameter" } [/block] The 'fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"[site_id]\":\n {\n \"noauthCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"coupons\": [ \"coupon value 1\", \"coupon value 2\" ], // (optional)\n \"gift_cards\": [ { \"number\": \"number\", \"pin\": \"pin\" } ], // (optional)\n \"shipping_option\": { \"cheapest or fastest\" }, // (optional)\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "noauthCheckout (Guest)" }, { "code": "{\n \"[site_id]\":\n {\n \"authCheckout\": { required checkout fields },\n \"login\": { \"username\": \"store account username or email\", \"password\": \"store account password\" },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"coupon\": \"coupon value\", // optional\n \"gift_card\": { \"number\": \"number\", \"pin\": \"pin\") }, // optional\n \"shipping_option\": { \"cheapest or fastest\" }, // optional\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "authCheckout (Store account)" }, { "code": "{\n \"[site_id]\":\n {\n \"localCheckout\": { required checkout fields },\n \"addToCart\": {\n \"[productMD5_1]\": \"required product fields\",\n \"[productMD5_2]\": \"required product fields\",\n },\n \"pickup\": {\n \"[productMD5_1]\": \"Mountain View\",\n \"[productMD5_2]\": \"Mountain View\",\n },\n \"coupon\": \"coupon value\", // optional\n \"gift_card\": { \"number\": \"number\", \"pin\": \"pin\") }, // optional\n },\n \"[site_id_2]\": { .. }\n}", "language": "json", "name": "localCheckout (Pickup from store)" } ] } [/block] To keep things simple if you're building your own native checkout always ask for the following fields, and send them all with each site_id. The possible keys and values are listed [here](http://docs.twotap.com/docs/possible-keys-and-values). [block:code] { "codes": [ { "code": " [ \n 'email',\n 'shipping_first_name',\n 'shipping_last_name',\n 'shipping_address',\n 'shipping_city',\n 'shipping_state',\n 'shipping_country',\n 'shipping_zip',\n 'shipping_telephone',\n 'billing_first_name',\n 'billing_last_name',\n 'billing_address',\n 'billing_city',\n 'billing_state',\n 'billing_country',\n 'billing_zip',\n 'billing_telephone',\n 'card_type',\n 'card_number',\n 'card_name',\n 'expiry_date_year',\n 'expiry_date_month',\n 'cvv'\n ]", "language": "json", "name": "noauthCheckout (Guest) and authCheckout (Store account)" }, { "code": " [ \n 'email',\n 'shipping_first_name', // this is the designated pickup person.\n 'shipping_last_name',\n 'shipping_zip', // this is the zip for the pickup store.\n 'billing_first_name',\n 'billing_last_name',\n 'billing_address',\n 'billing_city',\n 'billing_state',\n 'billing_country',\n 'billing_zip',\n 'billing_telephone',\n 'card_type',\n 'card_number',\n 'card_name',\n 'expiry_date_year',\n 'expiry_date_month',\n 'cvv'\n ]", "language": "json", "name": "localCheckout (Pickup from store)" } ] } [/block] [block:callout] { "type": "info", "title": "Addresses", "body": "Due to the way most retailers handle validations (which is turn a factor of the carriers) the only characters allowed for addresses are alphanumerical, comma, dot, space, and /. You can use /fields_input_validate to check your information ahead of time.\n\nTo break an address into address_line_1 and address_line_2 add one comma, eg:\n\"106 Shotwell St, Unit 41\"" } [/block] [block:api-header] { "type": "basic", "title": "The 'affiliate_links' parameter" } [/block] The 'affiliate_links' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{ \n \"[site_id]\": \"affiliate_link\" \n}", "language": "json", "name": "One affiliate link per site" }, { "code": "{ \n \"[site_id]\": { \n \"[productMD5]\": \"affiliate_link\" \n } \n}", "language": "json", "name": "One affiliate link per product" } ] } [/block] [block:api-header] { "type": "basic", "title": "The 'confirm' parameter" } [/block] Instead of polling /purchase/status Two Tap can send callbacks as it's processing the purchase. See the [SMS API](https://old.twotap.com/docs/#api_sms_flow) flow or [HTTP API](https://old.twotap.com/docs/#api_http_flow) flow. [block:code] { "codes": [ { "code": " { \n method: 'http', \n http_confirm_url: 'https://your_confirm_endpoint', \n http_update_url: 'https://your_update_endpoint',\n skip_confirm: '(optional and dangerous) YOUR_PRIVATE_TOKEN'\n }", "language": "json" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f845","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\npurchase_id = ARGV[0]\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/purchase/status?public_token=PUBLIC_TOKEN&purchase_id=#{purchase_id}\"\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\nPURCHASE_ID=PURCHASE_ID\n\ncurl https://api.twotap.com/v1.0/purchase/status?public_token=$PUBLIC_TOKEN\\&purchase_id=$PURCHASE_ID","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\n\npublic_token = 'PUBLIC_TOKEN'\npurchase_id = 'PURCHASE_ID'\nr = requests.get('https://api.twotap.com/v1.0/purchase/status?public_token=' + public_token + '&purchase_id=' + purchase_id)\nprint(r.json())","language":"python"},{"code":"$.get(\"https://api.twotap.com/v1.0/purchase/status?public_token=PUBLIC_TOKEN&purchase_id=PURCHASE_ID\", function(data, status) {\n  console.log(data);\n})","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\nvar purchase_id = 'PURCHASE_ID';\nrequest({\n  url: 'https://api.twotap.com/v1.0/purchase/status?public_token=' + public_token + '&purchase_id=' + purchase_id,\n  method: \"GET\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\n\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PUBLIC_TOKEN';\n$purchase_id = 'PURCHASE_ID';\n$url = 'https://api.twotap.com/v1.0/purchase/status?public_token='.$public_token.'&purchase_id='.$purchase_id;\n$response = Requests::get($url);\necho $response->body;\n\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n)\n\nfunc main() {\n    public_token := \"PUBLIC_TOKEN\"\n    purchase_id := \"PURCHASE_ID\"\n    url := \"https://api.twotap.com/v1.0/purchase/status?public_token=\" + public_token + \"&purchase_id=\" + purchase_id\n    req, err := http.NewRequest(\"GET\", url, nil)\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var public_token = \"PUBLIC_TOKEN\";\n      var purchase_id = \"PURCHASE_ID\";\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase/status?public_token=\" + public_token + \"&purchase_id=\" + purchase_id);\n      var result = client.GetAsync (\"\").Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"params":[{"_id":"55a30d38ef69351700664e69","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"query"},{"_id":"55a2a796ef69351700664dc5","ref":"","required":true,"desc":"The purchase's id.","default":"","type":"string","name":"purchase_id","in":"query"}],"results":{"codes":[{"name":"still_processing","code":"{\n\t\"purchase_id\": \"57786063dfeb41503dcac289\",\n\t\"user_id\": null,\n\t\"created_at\": \"2016-07-03T00:46:27.583Z\",\n\t\"status\": \"info_running\",\n\t\"destination\": \"domestic\",\n\t\"test_mode\": null,\n\t\"notes\": null,\n\t\"used_profiles\": null,\n\t\"unique_token\": \"3043\",\n\t\"sites\": {\n\t\t\"5225da1055a0f96c8b000004\": {\n\t\t\t\"info\": {\n\t\t\t\t\"url\": \"target.com\",\n\t\t\t\t\"name\": \"Target\",\n\t\t\t\t\"logo\": \"https://core.twotap.com/system/sites/logos/5225/da10/55a0/f96c/8b00/0004/small/5225da1055a0f96c8b000004.png?1467506740775\"\n\t\t\t},\n\t\t\t\"prices\": {},\n\t\t\t\"details\": {},\n\t\t\t\"failed_to_add_to_cart\": null,\n\t\t\t\"order_id\": null,\n\t\t\t\"products\": {\n\t\t\t\t\"e987cc0e00b50b6edb0b785ca0ce3efb\": {\n\t\t\t\t\t\"title\": \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\",\n\t\t\t\t\t\"price\": \"$47.99\",\n\t\t\t\t\t\"original_price\": \"$79.99\",\n\t\t\t\t\t\"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n\t\t\t\t\t\"alt_images\": [\"http://target.scene7.com/is/image/Target/12877464?wid=800\" ], \n\t\t\t\t\t\"description\": \"Product description\",\n\t\t\t\t\t\"returns\": \"Return policy\",\n\t\t\t\t\t\"categories\": [\"home\", \"dining & entertaining\", \"flatware\", \"flatware sets\", \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\"],\n\t\t\t\t\t\"extra_info\": \"\",\n\t\t\t\t\t\"pickup_support\": true,\n\t\t\t\t\t\"required_field_names\": [\"size\", \"quantity\"],\n\t\t\t\t\t\"required_field_values\": {\n\t\t\t\t\t\t\"size\": [{\n\t\t\t\t\t\t\t\"extra_info\": \"\",\n\t\t\t\t\t\t\t\"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n\t\t\t\t\t\t\t\"price\": \"$47.99\",\n\t\t\t\t\t\t\t\"text\": \"A\",\n\t\t\t\t\t\t\t\"value\": \"A\",\n\t\t\t\t\t\t}, {\n              ...\n\t\t\t\t\t\t}]\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\n\t\t\t\t\t\"required_fields\": {\n\t\t\t\t\t\t\"size\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"SELECT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"select-one\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"quantity\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"INPUT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"text\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": \"done\",\n\t\t\t\t\t\"clean_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\t\t\t\t\t\"original_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\t\t\t\t\t\"input_fields\": {\n\t\t\t\t\t\t\"quantity\": \"1\",\n\t\t\t\t\t\t\"size\": \"H\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"status\": \"still_processing\",\n\t\t\t\"last_message\": \"Adding product RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern.\",\n\t\t\t\"percent_done\": 22.470238095238095\n\t\t}\n\t},\n\t\"message\": \"still_processing\",\n\t\"description\": \"Still processing.\"\n}","language":"json","status":200},{"code":"{\n\t\"purchase_id\": \"57786183dfeb41503dcac292\",\n\t\"user_id\": null,\n\t\"created_at\": \"2016-07-03T00:51:15.807Z\",\n\t\"status\": \"confirm_finished\",\n\t\"total_prices\": {\n\t\t\"final_price\": \"$52.19\",\n\t\t\"shipping_price\": \"$0.00\",\n\t\t\"sales_tax\": \"$4.20\"\n\t},\n\t\"destination\": \"domestic\",\n\t\"test_mode\": null,\n\t\"notes\": null,\n\t\"used_profiles\": null,\n\t\"unique_token\": \"7034\",\n\t\"pending_confirm\": false,\n\t\"sites\": {\n\t\t\"5225da1055a0f96c8b000004\": {\n\t\t\t\"info\": {\n\t\t\t\t\"url\": \"target.com\",\n\t\t\t\t\"name\": \"Target\",\n\t\t\t\t\"logo\": \"https://core.twotap.com/system/sites/logos/5225/da10/55a0/f96c/8b00/0004/small/5225da1055a0f96c8b000004.png?1467506923931\"\n\t\t\t},\n\t\t\t\"prices\": {\n\t\t\t\t\"final_price\": \"$52.19\",\n\t\t\t\t\"shipping_price\": \"free\",\n\t\t\t\t\"sales_tax\": \"$4.20\"\n\t\t\t},\n\t\t\t\"details\": {\n\t\t\t\t\"shipping_estimate\": \"RiverRidge® 46 Pc Personalized Flatware - Bouquet Pattern - H by 07/13\"\n\t\t\t},\n\t\t\t\"failed_to_add_to_cart\": null,\n\t\t\t\"products\": {\n\t\t\t\t\"e987cc0e00b50b6edb0b785ca0ce3efb\": {\n\t\t\t\t\t\"title\": \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\",\n\t\t\t\t\t\"price\": \"$47.99\",\n\t\t\t\t\t\"original_price\": \"$79.99\",\n\t\t\t\t\t\"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n\t\t\t\t\t\"alt_images\": [\"http://target.scene7.com/is/image/Target/12877464?wid=800\" ], \n\t\t\t\t\t\"description\": \"Product description\",\n\t\t\t\t\t\"returns\": \"Return policy\",\n\t\t\t\t\t\"categories\": [\"home\", \"dining & entertaining\", \"flatware\", \"flatware sets\", \"RiverRidge® 46 Pc Personalized Flatware Set - Bouquet Pattern\"],\n\t\t\t\t\t\"extra_info\": \"\",\n\t\t\t\t\t\"pickup_support\": true,\n\t\t\t\t\t\"required_field_names\": [\"size\", \"quantity\"],\n\t\t\t\t\t\"required_field_values\": {\n\t\t\t\t\t\t\"size\": [{\n\t\t\t\t\t\t\t\"extra_info\": \"\",\n\t\t\t\t\t\t\t\"image\": \"http://target.scene7.com/is/image/Target/12877464?wid=800\",\n\t\t\t\t\t\t\t\"price\": \"$47.99\",\n\t\t\t\t\t\t\t\"text\": \"A\",\n\t\t\t\t\t\t\t\"value\": \"A\",\n\t\t\t\t\t\t}, {\n              ...\n\t\t\t\t\t\t}]\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\n\t\t\t\t\t\"required_fields\": {\n\t\t\t\t\t\t\"size\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"SELECT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"select-one\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"quantity\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"INPUT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"text\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\t\t\t\t\t\"discounted_price\": null,\n\t\t\t\t\t\"required_fields\": {\n\t\t\t\t\t\t\"size\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"SELECT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"select-one\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"quantity\": {\n\t\t\t\t\t\t\t\"data\": [{\n\t\t\t\t\t\t\t\t\"input_name\": \"INPUT\",\n\t\t\t\t\t\t\t\t\"input_type\": \"text\"\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": \"done\",\n\t\t\t\t\t\"clean_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\t\t\t\t\t\"original_url\": \"http://www.target.com/p/46-pc-bouquet-personalized-flatware-set/-/A-12876605\",\n\t\t\t\t\t\"input_fields\": {\n\t\t\t\t\t\t\"size\": \"H\",\n\t\t\t\t\t\t\"quantity\": \"1\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"status\": \"failed\",\n\t\t\t\"status_messages\": [\"card number\", \"We're sorry. The credit card you entered could not be processed. Please double-check the information and enter it again or try a different credit card. If you're sure the information you provided is correct, please contact your credit card company.\"],\n      \"status_reason\": \"bad_payment\"\n\t\t}\n\t},\n\t\"message\": \"has_failures\"\n}","language":"json","status":200,"name":"done"}]},"settings":"","url":"/purchase/status"},"body":"Call '/purchase/status' to see the status of a '/purchase' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Response description\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"purchase_id\",\n    \"0-1\": \"The purchase's id.\",\n    \"1-0\": \"message\",\n    \"1-1\": \"If Two Tap has completed the request. This can be: 'still_processing', 'has_failures', or 'done'.\",\n    \"2-0\": \"description\",\n    \"2-1\": \"A more human-friendly description of the message.\",\n    \"4-0\": \"pending_confirm\",\n    \"4-1\": \"Boolean, true or false. Whether /purchase/confirm was called.\",\n    \"9-0\": \"sites\",\n    \"12-0\": \"sites[id][prices]\",\n    \"9-1\": \"A hash that contains information grouped by a siteID.\",\n    \"12-1\": \"A hash that contains always contains the final_price, and may also contain a shipping_price, the sales_tax, a gift_card_value (if sent), a coupon_value (if sent).\\n\\n**Only available for domestic purchases.**\",\n    \"13-0\": \"sites[id][details]\",\n    \"13-1\": \"Contains various information about the checkout session as retrieved from the retailer site.\\n\\n**Only available for domestic purchases.**\",\n    \"17-0\": \"sites[id][order_id]\",\n    \"17-1\": \"After 'confirm' finished this could contain an order id.\\n\\n**Only available for domestic purchases.**\",\n    \"20-0\": \"sites[id][info]\",\n    \"20-1\": \"A hash that contains the 'name', 'url', and 'logo' of the site.\",\n    \"21-0\": \"sites[id][status]\",\n    \"21-1\": \"The site status.\\n\\nFor domestic orders this can be: 'still_processing', 'failed' or 'done'.\\n\\nFor international orders this can be:  'still_processing', 'has_failures' (if Two Tap removed products), 'failed', or 'done'.\",\n    \"22-0\": \"sites[id][status_messages]\",\n    \"22-1\": \"An array of errors that is present if status is 'failed'.\",\n    \"24-0\": \"sites[id][last_message]\",\n    \"24-1\": \"The latest status message sent by the request processor. This is used during the 'still_processing' phase.\",\n    \"14-0\": \"sites[id][details][shipping_estimate]\",\n    \"14-1\": \"The store's estimated delivery date.\\n\\n**Only available for domestic purchases.**\",\n    \"15-0\": \"sites[id][details][active_payment_method]\",\n    \"15-1\": \"authCheckout only. Information about the payment method we used with a store account checkout.\\n\\n**Only available for domestic purchases.**\",\n    \"16-0\": \"sites[id][details][active_shipping_address]\",\n    \"16-1\": \"authCheckout only. Information about the shipping address we used with a store account checkout.\\n\\n**Only available for domestic purchases.**\",\n    \"19-0\": \"sites[id][failed_to_add_to_cart]\",\n    \"19-1\": \"In case the purchase failed because we couldn't add a product to the cart this will contain that product's MD5. Match this with /cart/status responses.\",\n    \"3-0\": \"state\",\n    \"3-1\": \"The state of the purchase. Can be:\\n'info_running', 'info_finished', 'confirm_running', 'confirm_finished', 'waiting_for_tracking_links', 'to_warehouse', 'to_shopper', 'done'.\\n\\n\\n**Only available for international purchases.**\",\n    \"5-0\": \"created_at\",\n    \"5-1\": \"When the purchase was created.\",\n    \"6-0\": \"total_prices\",\n    \"6-1\": \"A hash that contains the total cart prices: final_price, shipping_price, sales_tax, coupon_value, discount_value, subtotal.\\n\\n**Available for both domestic and international purchases.**\",\n    \"7-0\": \"destination\",\n    \"7-1\": \"'domestic' or 'intl'.\",\n    \"8-0\": \"notes\",\n    \"8-1\": \"The information you sent with the /cart or /purchase calls.\",\n    \"18-0\": \"sites[id][remote_state]\",\n    \"18-1\": \"The status as returned by the retailer site. A hash key-ed by the product MD5.\\n\\n{ product_md5: 'status' }\\n\\nCan be: 'processing', 'to_shopper', 'done', 'cancelled'.\\n\\n**Only available for domestic purchases.**\",\n    \"23-0\": \"sites[id][status_reason]\",\n    \"23-1\": \"If the status has failed this field will tell you why. Possible values are: 'bad_payment', 'bad_billing_address', 'bad_shipping_address', 'verified_visa_3d_secure', 'oos' (out of stock), 'session_expired', or 'other'.\",\n    \"10-0\": \"sites[id][products]\",\n    \"10-1\": \"Product information. Similar to /cart/status.\",\n    \"11-0\": \"sites[id][removed_products]\",\n    \"11-1\": \"Products that Two Tap has removed from the purchase.\\n\\n**Only available for international purchases.**\"\n  },\n  \"cols\": 2,\n  \"rows\": 25\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T19:59:22.556Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":27,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"purchase-status","sync_unique":"","title":"/purchase/status","type":"get","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

get/purchase/status


Query Params

public_token:
required
string
Your Two Tap public token.
purchase_id:
required
string
The purchase's id.
Call '/purchase/status' to see the status of a '/purchase' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'. [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "purchase_id", "0-1": "The purchase's id.", "1-0": "message", "1-1": "If Two Tap has completed the request. This can be: 'still_processing', 'has_failures', or 'done'.", "2-0": "description", "2-1": "A more human-friendly description of the message.", "4-0": "pending_confirm", "4-1": "Boolean, true or false. Whether /purchase/confirm was called.", "9-0": "sites", "12-0": "sites[id][prices]", "9-1": "A hash that contains information grouped by a siteID.", "12-1": "A hash that contains always contains the final_price, and may also contain a shipping_price, the sales_tax, a gift_card_value (if sent), a coupon_value (if sent).\n\n**Only available for domestic purchases.**", "13-0": "sites[id][details]", "13-1": "Contains various information about the checkout session as retrieved from the retailer site.\n\n**Only available for domestic purchases.**", "17-0": "sites[id][order_id]", "17-1": "After 'confirm' finished this could contain an order id.\n\n**Only available for domestic purchases.**", "20-0": "sites[id][info]", "20-1": "A hash that contains the 'name', 'url', and 'logo' of the site.", "21-0": "sites[id][status]", "21-1": "The site status.\n\nFor domestic orders this can be: 'still_processing', 'failed' or 'done'.\n\nFor international orders this can be: 'still_processing', 'has_failures' (if Two Tap removed products), 'failed', or 'done'.", "22-0": "sites[id][status_messages]", "22-1": "An array of errors that is present if status is 'failed'.", "24-0": "sites[id][last_message]", "24-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase.", "14-0": "sites[id][details][shipping_estimate]", "14-1": "The store's estimated delivery date.\n\n**Only available for domestic purchases.**", "15-0": "sites[id][details][active_payment_method]", "15-1": "authCheckout only. Information about the payment method we used with a store account checkout.\n\n**Only available for domestic purchases.**", "16-0": "sites[id][details][active_shipping_address]", "16-1": "authCheckout only. Information about the shipping address we used with a store account checkout.\n\n**Only available for domestic purchases.**", "19-0": "sites[id][failed_to_add_to_cart]", "19-1": "In case the purchase failed because we couldn't add a product to the cart this will contain that product's MD5. Match this with /cart/status responses.", "3-0": "state", "3-1": "The state of the purchase. Can be:\n'info_running', 'info_finished', 'confirm_running', 'confirm_finished', 'waiting_for_tracking_links', 'to_warehouse', 'to_shopper', 'done'.\n\n\n**Only available for international purchases.**", "5-0": "created_at", "5-1": "When the purchase was created.", "6-0": "total_prices", "6-1": "A hash that contains the total cart prices: final_price, shipping_price, sales_tax, coupon_value, discount_value, subtotal.\n\n**Available for both domestic and international purchases.**", "7-0": "destination", "7-1": "'domestic' or 'intl'.", "8-0": "notes", "8-1": "The information you sent with the /cart or /purchase calls.", "18-0": "sites[id][remote_state]", "18-1": "The status as returned by the retailer site. A hash key-ed by the product MD5.\n\n{ product_md5: 'status' }\n\nCan be: 'processing', 'to_shopper', 'done', 'cancelled'.\n\n**Only available for domestic purchases.**", "23-0": "sites[id][status_reason]", "23-1": "If the status has failed this field will tell you why. Possible values are: 'bad_payment', 'bad_billing_address', 'bad_shipping_address', 'verified_visa_3d_secure', 'oos' (out of stock), 'session_expired', or 'other'.", "10-0": "sites[id][products]", "10-1": "Product information. Similar to /cart/status.", "11-0": "sites[id][removed_products]", "11-1": "Products that Two Tap has removed from the purchase.\n\n**Only available for international purchases.**" }, "cols": 2, "rows": 25 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Call '/purchase/status' to see the status of a '/purchase' request. The response is different if response['message'] is 'still_processing', 'failed', or 'done'. [block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "purchase_id", "0-1": "The purchase's id.", "1-0": "message", "1-1": "If Two Tap has completed the request. This can be: 'still_processing', 'has_failures', or 'done'.", "2-0": "description", "2-1": "A more human-friendly description of the message.", "4-0": "pending_confirm", "4-1": "Boolean, true or false. Whether /purchase/confirm was called.", "9-0": "sites", "12-0": "sites[id][prices]", "9-1": "A hash that contains information grouped by a siteID.", "12-1": "A hash that contains always contains the final_price, and may also contain a shipping_price, the sales_tax, a gift_card_value (if sent), a coupon_value (if sent).\n\n**Only available for domestic purchases.**", "13-0": "sites[id][details]", "13-1": "Contains various information about the checkout session as retrieved from the retailer site.\n\n**Only available for domestic purchases.**", "17-0": "sites[id][order_id]", "17-1": "After 'confirm' finished this could contain an order id.\n\n**Only available for domestic purchases.**", "20-0": "sites[id][info]", "20-1": "A hash that contains the 'name', 'url', and 'logo' of the site.", "21-0": "sites[id][status]", "21-1": "The site status.\n\nFor domestic orders this can be: 'still_processing', 'failed' or 'done'.\n\nFor international orders this can be: 'still_processing', 'has_failures' (if Two Tap removed products), 'failed', or 'done'.", "22-0": "sites[id][status_messages]", "22-1": "An array of errors that is present if status is 'failed'.", "24-0": "sites[id][last_message]", "24-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase.", "14-0": "sites[id][details][shipping_estimate]", "14-1": "The store's estimated delivery date.\n\n**Only available for domestic purchases.**", "15-0": "sites[id][details][active_payment_method]", "15-1": "authCheckout only. Information about the payment method we used with a store account checkout.\n\n**Only available for domestic purchases.**", "16-0": "sites[id][details][active_shipping_address]", "16-1": "authCheckout only. Information about the shipping address we used with a store account checkout.\n\n**Only available for domestic purchases.**", "19-0": "sites[id][failed_to_add_to_cart]", "19-1": "In case the purchase failed because we couldn't add a product to the cart this will contain that product's MD5. Match this with /cart/status responses.", "3-0": "state", "3-1": "The state of the purchase. Can be:\n'info_running', 'info_finished', 'confirm_running', 'confirm_finished', 'waiting_for_tracking_links', 'to_warehouse', 'to_shopper', 'done'.\n\n\n**Only available for international purchases.**", "5-0": "created_at", "5-1": "When the purchase was created.", "6-0": "total_prices", "6-1": "A hash that contains the total cart prices: final_price, shipping_price, sales_tax, coupon_value, discount_value, subtotal.\n\n**Available for both domestic and international purchases.**", "7-0": "destination", "7-1": "'domestic' or 'intl'.", "8-0": "notes", "8-1": "The information you sent with the /cart or /purchase calls.", "18-0": "sites[id][remote_state]", "18-1": "The status as returned by the retailer site. A hash key-ed by the product MD5.\n\n{ product_md5: 'status' }\n\nCan be: 'processing', 'to_shopper', 'done', 'cancelled'.\n\n**Only available for domestic purchases.**", "23-0": "sites[id][status_reason]", "23-1": "If the status has failed this field will tell you why. Possible values are: 'bad_payment', 'bad_billing_address', 'bad_shipping_address', 'verified_visa_3d_secure', 'oos' (out of stock), 'session_expired', or 'other'.", "10-0": "sites[id][products]", "10-1": "Product information. Similar to /cart/status.", "11-0": "sites[id][removed_products]", "11-1": "Products that Two Tap has removed from the purchase.\n\n**Only available for international purchases.**" }, "cols": 2, "rows": 25 } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f846","api":{"examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\npurchase_id = ARGV[0]\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase/confirm?private_token=PRIVATE_TOKEN\", { purchase_id: purchase_id }\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\nPRIVATE_TOKEN=PRIVATE_TOKEN\nPURCHASE_ID=PURCHASE_ID\n\ncurl https://api.twotap.com/v1.0/purchase/confirm?private_token=$PRIVATE_TOKEN --header 'Content-Type: application/json' --data-binary '{\"purchase_id\" : \"$PURCHASE_ID\"}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\nprivate_token = 'PRIVATE_TOKEN'\npayload = {\"purchase_id\": \"PURCHASE_ID\"}\nr = requests.post('https://api.twotap.com/v1.0/purchase/confirm?private_token=' + private_token,\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\nprint(r.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/purchase/confirm?private_token=PRIVATE_TOKEN', {\n  \"purchase_id\": \"PURCHASE_ID\"\n}, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nvar private_token = 'PRIVATE_TOKEN';\nrequest({\n  url: 'https://api.twotap.com/v1.0/purchase/confirm?private_token=' + private_token,\n  json: {\"purchase_id\": \"PURCHASE_ID\"},\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$private_token = 'PRIVATE_TOKEN';\n$url = 'https://api.twotap.com/v1.0/purchase/confirm?private_token='.$private_token;\n$payload = array(\"purchase_id\" => \"PURCHASE_ID\");\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    private_token := \"PRIVATE_TOKEN\"\n    url := \"https://api.twotap.com/v1.0/purchase/confirm?private_token=\" + private_token\n    var jsonStr = []byte(`{\"purchase_id\": \"PURCHASE_ID\"}`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      var private_token = \"PRIVATE_TOKEN\";\n      var purchase_id = \"PURCHASE_ID\";\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/purchase/confirm?private_token=\" + private_token);\n      dynamic payload = new ExpandoObject ();\n      payload.purchase_id = purchase_id;\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"results":{"codes":[{"name":"","code":"{\n  \"purchase_id\": \"50f414b9e6a4869bf6000010\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\",\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a30d5389d84c0d002af0af","ref":"","required":true,"desc":"Your Two Tap PRIVATE token.","default":"","type":"string","name":"private_token","in":"body"},{"_id":"55a2a86acfd73f2100f19757","ref":"","required":true,"desc":"The purchase id that is sent by '/purchase'.","default":"","type":"string","name":"purchase_id","in":"body"},{"_id":"55a2a86acfd73f2100f19756","ref":"","required":false,"desc":"*(Optional)* fake_confirm. A way to test the API the interface without making actual purchases.","default":"","type":"string","name":"test_mode","in":"body"}],"url":"/purchase/confirm"},"body":"Purchase confirm finalizes the order. Only perform this request **server side** as it uses your **private token**.\n\nThis request is available for **5 minutes** after Two Tap calls your confirm callback or /purchase/status is in the pending_confirm: true state.","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T20:14:24.761Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":28,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"purchase-confirm","sync_unique":"","title":"/purchase/confirm","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/purchase/confirm


Body JSON

private_token:
required
string
Your Two Tap PRIVATE token.
purchase_id:
required
string
The purchase id that is sent by '/purchase'.
test_mode:
string
*(Optional)* fake_confirm. A way to test the API the interface without making actual purchases.
Purchase confirm finalizes the order. Only perform this request **server side** as it uses your **private token**. This request is available for **5 minutes** after Two Tap calls your confirm callback or /purchase/status is in the pending_confirm: true state.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Purchase confirm finalizes the order. Only perform this request **server side** as it uses your **private token**. This request is available for **5 minutes** after Two Tap calls your confirm callback or /purchase/status is in the pending_confirm: true state.
{"__v":1,"_id":"57780374ea758f0e00e6f847","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\ncart_id = ARGV[0]\n\n# A hash like { field_key: field_value }\nflat_fields_input = { \n  shipping_first_name: 'name',\n  shipping_address: 'address' \n}\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/fields_input_validate?public_token=PUBLIC_TOKEN\", { \n  cart_id: cart_id,\n  flat_fields_input: flat_fields_input \n}\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\ncurl \"https://api.twotap.com/v1.0/fields_input_validate?public_token=$PUBLIC_TOKEN\" --header 'Content-Type: application/json' --data-binary '\n{\n\t\"cart_id\": \"CART_ID\",\n  \"flat_fields_input\": {\n\t  \"shipping_first_name\": \"name\",\n    \"shipping_address\": \"address\"\n  }\n}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\npublic_token = 'PUBLIC_TOKEN'\n\npayload = {\n  \"cart_id\": \"CART_ID\",\n  \"flat_fields_input\": {\n    \"shipping_first_name\": \"name\",\n    \"shipping_address\": \"address\"\n  }\n}\nr = requests.post('https://api.twotap.com/v1.0/fields_input_validate?public_token=' + public_token, data=json.dumps(payload), headers={'Content-Type': 'application/json'})\nprint(r.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/fields_input_validate?public_token=PUBLIC_TOKEN', {\n  \"cart_id\": \"CART_ID\",\n  \"flat_fields_input\": {\n    \"shipping_first_name\": \"name\",\n    \"shipping_address\": \"address\"\n  }\n}, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nvar public_token = 'PUBLIC_TOKEN';\n\nrequest({\n  url: 'https://api.twotap.com/v1.0/fields_input_validate?public_token=' + public_token',\n  json: {   \n  \t\"cart_id\": \"CART_ID\",\n    \"flat_fields_input\": {\n      \"shipping_first_name\": \"name\",\n      \"shipping_address\": \"address\"\n  },\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});var request = require(\"request\");\nrequest({\n  url: 'https://api.twotap.com/v1.0/fields_input_validate',\n  json: {\"shipping_first_name\": \"name\", \"shipping_address\": \"address\"},\n  method: \"POST\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = 'https://api.twotap.com/v1.0/fields_input_validate?public_token='.$public_token;\n$payload = array(\n  \"cart_id\" => \"CART_ID\",\n  \"flat_fields_input\" => array(\n    \"shipping_first_name\" => \"name\",\n    \"shipping_address\" => \"address\"\n  )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    url := \"https://api.twotap.com/v1.0/fields_input_validate?public_token=\" + public_token\n    var jsonStr = []byte(`{\n  \"cart_id\": \"CART_ID\",\n  \"flat_fields_input\": {\n    \"shipping_first_name\": \"name\",\n    \"shipping_address\": \"address\"\n   }\n}`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"}]},"params":[{"_id":"578ff5fa29f79c19000892cd","default":"","desc":"The cart id that is sent by '/cart'.","in":"body","name":"cart_id","ref":"","required":false,"type":"string"},{"_id":"578ff5fa29f79c19000892cc","ref":"","in":"body","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token"},{"_id":"55a2a9afa50aca1700782ea4","ref":"","in":"body","required":true,"desc":"A hash with input values.","default":"","type":"object","name":"flat_fields_input"}],"results":{"codes":[{"name":"","code":"{\n  \"message\": \"done or bad_required_fields\",\n  \"description\": \"A string that lists the issues.\"\n}","language":"json","status":200}]},"settings":"","url":"/fields_input_validate"},"body":"Let's say you are capturing data from the user. Two Tap requires it to be in a certain format or it will reject it. This API method allows you to validate it before sending it with the purchase.\n\nThis endpoint does not do address validation. You have to use a service like [Lob](https://lob.com/) or [EasyPost](https://www.easypost.com/) on your end.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'flat_fields_input' parameter\"\n}\n[/block]\nThe 'flat_fields_input' parameter is a hash that looks like below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"shipping_first_name\\\": \\\"shipping first name\\\",\\n  \\\"shipping_last_name\\\": \\\"shipping last name\\\",\\n  [ and so on ]\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T20:21:30.064Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":29,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"validating-input-fields","sync_unique":"","title":"/fields_input_validate","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/fields_input_validate


Body JSON

cart_id:
string
The cart id that is sent by '/cart'.
public_token:
required
string
Your Two Tap public token.
flat_fields_input:
required
object
A hash with input values.
Let's say you are capturing data from the user. Two Tap requires it to be in a certain format or it will reject it. This API method allows you to validate it before sending it with the purchase. This endpoint does not do address validation. You have to use a service like [Lob](https://lob.com/) or [EasyPost](https://www.easypost.com/) on your end. [block:api-header] { "type": "basic", "title": "The 'flat_fields_input' parameter" } [/block] The 'flat_fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"shipping_first_name\": \"shipping first name\",\n \"shipping_last_name\": \"shipping last name\",\n [ and so on ]\n}", "language": "json" } ] } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Let's say you are capturing data from the user. Two Tap requires it to be in a certain format or it will reject it. This API method allows you to validate it before sending it with the purchase. This endpoint does not do address validation. You have to use a service like [Lob](https://lob.com/) or [EasyPost](https://www.easypost.com/) on your end. [block:api-header] { "type": "basic", "title": "The 'flat_fields_input' parameter" } [/block] The 'flat_fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "{\n \"shipping_first_name\": \"shipping first name\",\n \"shipping_last_name\": \"shipping last name\",\n [ and so on ]\n}", "language": "json" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f848","api":{"examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/quicky?public_token=PUBLIC_TOKEN&sms_confirm_url=SMS_CONFIRM_URL&phone=PHONE&message=MESSAGE&products=PRODUCTS\"\n\nputs response.body","language":"ruby"}]},"results":{"codes":[{"name":"","code":"{\n  \"message\": \"done\",\n  \"description\": \"Message sent to PHONE.\",\n  \"contents\": \"We heard you'd like to buy some products. Tap here to start: http://ttap.co/ID.\"\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a30d66ef69351700664e6b","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"query"},{"_id":"55a2aa63a50aca1700782ea9","ref":"","required":true,"desc":"A list of products urls separated by commas. We encourage you to encode each product url beforehand.","default":"","type":"string","name":"products","in":"query"},{"_id":"55a2aa63a50aca1700782ea8","ref":"","required":true,"desc":"Quicky defaults to the SMS flow, which requires the implementation of a confirm url.","default":"","type":"string","name":"sms_confirm_url","in":"query"},{"_id":"55a2aa63a50aca1700782ea7","ref":"","required":true,"desc":"The shopper's phone number. US only for now.","default":"","type":"string","name":"phone","in":"query"},{"_id":"55a2aa63a50aca1700782ea6","ref":"","required":false,"desc":"(Optional) The message the shopper would receive. eg: \"We heard you'd like to buy some products. Tap here to start: %%URL%%.\"","default":"","type":"string","name":"message","in":"query"}],"url":"/quicky"},"body":"Quicky is Two Tap's version of the [Amazon Dash Replenishment Service](https://www.amazon.com/oc/dash-replenishment-service). When you hit this endpoint the shopper will receive an SMS with a link to purchase certain products.\n\nYou still have to implement the [SMS Confirm URL](https://old.twotap.com/docs/#api_sms_flow) in your backend.","category":"57780374ea758f0e00e6f822","createdAt":"2015-07-10T20:25:59.468Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":30,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"quicky","sync_unique":"","title":"/quicky","type":"get","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

get/quicky


Query Params

public_token:
required
string
Your Two Tap public token.
products:
required
string
A list of products urls separated by commas. We encourage you to encode each product url beforehand.
sms_confirm_url:
required
string
Quicky defaults to the SMS flow, which requires the implementation of a confirm url.
phone:
required
string
The shopper's phone number. US only for now.
message:
string
(Optional) The message the shopper would receive. eg: "We heard you'd like to buy some products. Tap here to start: %%URL%%."
Quicky is Two Tap's version of the [Amazon Dash Replenishment Service](https://www.amazon.com/oc/dash-replenishment-service). When you hit this endpoint the shopper will receive an SMS with a link to purchase certain products. You still have to implement the [SMS Confirm URL](https://old.twotap.com/docs/#api_sms_flow) in your backend.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Quicky is Two Tap's version of the [Amazon Dash Replenishment Service](https://www.amazon.com/oc/dash-replenishment-service). When you hit this endpoint the shopper will receive an SMS with a link to purchase certain products. You still have to implement the [SMS Confirm URL](https://old.twotap.com/docs/#api_sms_flow) in your backend.
{"category":"57780374ea758f0e00e6f822","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f849","createdAt":"2015-07-10T20:33:48.522Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\npurchase_id = ARGV[0]\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/supported_sites\"\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\ncurl https://api.twotap.com/v1.0/supported_sites","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\n\nr = requests.get('https://api.twotap.com/v1.0/supported_sites');\nprint(r.json())","language":"python"},{"code":"$.get(\"https://api.twotap.com/v1.0/supported_sites\", function(data, status) {\n  console.log(data);\n})","language":"javascript"},{"code":"var request = require(\"request\");\nrequest({\n  url: 'https://api.twotap.com/v1.0/supported_sites',\n  method: \"GET\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = 'https://api.twotap.com/v1.0/supported_sites';\n$response = Requests::get($url);\necho $response->body;\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n)\n\nfunc main() {\n    url := \"https://api.twotap.com/v1.0/supported_sites\"\n    req, err := http.NewRequest(\"GET\", url, nil)\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/supported_sites\");\n      var result = client.GetAsync (\"\").Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"results":{"codes":[{"name":"","code":"[\n  {\n    \"id\": \"52d7a85ece04fabdcd000005\",\n    \"name\": \"Shoebuy\",\n    \"url\": \"shoebuy.com\",\n    \"logo\": \"https://core.twotap.com/system/recipes/logos/5374/e544/ce04/faea/d600/000f/small/Shoebuy_2.png?1400808613861\"\n  }\n  [..]\n]","language":"json","status":200}]},"settings":"","auth":"required","params":[],"url":"/supported_sites"},"isReference":false,"order":31,"body":"Query this url to get a list of our currently supported sites.","excerpt":"","slug":"supported-sites","type":"get","title":"/supported_sites","__v":0,"childrenPages":[]}

get/supported_sites


Query this url to get a list of our currently supported sites.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Query this url to get a list of our currently supported sites.
{"__v":0,"_id":"57cd65ba4bddd10e00c49973","api":{"auth":"required","examples":{"codes":[{"name":"","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\npurchase_id = ARGV[0]\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/coupons?private_token=PRIVATE_TOKEN\"\n\nputs response.body","language":"ruby"},{"code":"#!/bin/bash\n\nPRIVATE_TOKEN=PRIVATE_TOKEN\n\ncurl https://api.twotap.com/v1.0/coupons?private_token=$PRIVATE_TOKEN","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\n\nprivate_token = 'PRIVATE_TOKEN'\n\nr = requests.get('https://api.twotap.com/v1.0/coupons?private_token=' + private_token)\n\nprint(r.json())","language":"python"},{"code":"$.get(\"https://api.twotap.com/v1.0/coupons?private_token=PRIVATE_TOKEN\", function(data, status) {\n  console.log(data);\n})","language":"javascript"},{"code":"var request = require(\"request\");\nvar private_token = 'PRIVATE_TOKEN';\n\nrequest({\n  url: 'https://api.twotap.com/v1.0/coupons?private_token=' + private_token,\n  method: \"GET\"\n}, function (err, reponse, body) {\n  console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\n\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$public_token = 'PRIVATE_TOKEN';\n\n$url = 'https://api.twotap.com/v1.0/coupons?private_token='.$private_token;\n$response = Requests::get($url);\necho $response->body;\n\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n)\n\nfunc main() {\n    private_token := \"PRIVATE_TOKEN\"\n    url := \"https://api.twotap.com/v1.0/coupons?private_token=\" + private_token\n    req, err := http.NewRequest(\"GET\", url, nil)\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"}]},"params":[{"_id":"578ff5fa29f79c19000892cc","ref":"","in":"body","required":true,"desc":"Your Two Tap PRIVATE token.","default":"","type":"string","name":"private_token"}],"results":{"codes":[{"status":200,"language":"json","code":"[  \n   {  \n      \"site_id\":\"53fc5564ce04fabc27000019\",\n      \"code\":\"AFFSHOP1\",\n      \"label\":\"15% off any order.\",\n      \"rules\":[  \n         {  \n            \"free_shipping\":false,\n            \"sale\":false,\n            \"one_item\":false,\n            \"percentage_off\":15\n         }\n      ],\n      \"starts_at\":\"2014-04-01T07:00:00.000Z\",\n      \"ends_at\":\"2017-04-03T14:59:00.000Z\"\n   },\n   {  \n      \"site_id\":\"54817d1a69702d46e7100000\",\n      \"code\":\"AFFREG\",\n      \"label\":\"$7 off $70+ order.\",\n      \"rules\":[  \n         {  \n            \"free_shipping\":false,\n            \"sale\":false,\n            \"one_item\":false,\n            \"value_off\":7,\n            \"threshold\":70\n         }\n      ],\n      \"starts_at\":\"2015-02-06T08:00:00.000Z\",\n      \"ends_at\":\"2051-01-01T07:59:00.000Z\"\n   },\n   {  \n      \"site_id\":\"5643271869702d6af5000001\",\n      \"code\":\"CJ75\",\n      \"label\":\"5% off $75+ order.\",\n      \"rules\":[  \n         {  \n            \"free_shipping\":false,\n            \"sale\":false,\n            \"one_item\":false,\n            \"percentage_off\":5,\n            \"threshold\":75\n         }\n      ],\n      \"starts_at\":\"2008-11-13T08:00:00.000Z\",\n      \"ends_at\":\"2051-01-01T07:59:59.000Z\"\n   },\n   {  \n      \"site_id\":\"5576f02969702d6705080000\",\n      \"code\":\"TGSHOP15\",\n      \"label\":\"15% off any order.\",\n      \"rules\":[  \n         {  \n            \"free_shipping\":false,\n            \"sale\":false,\n            \"one_item\":false,\n            \"percentage_off\":15\n         }\n      ],\n      \"starts_at\":\"2016-04-05T07:00:00.000Z\",\n      \"ends_at\":\"2025-12-31T08:00:00.000Z\"\n   }\n]\n","name":""}]},"settings":"","url":"/coupons"},"body":"While Two Tap applies any coupon you send during /purchase it also has a database of active coupons.\n\nThe database is used at /cart/estimates in order to, well, estimate the coupon discount before actually starting the checkout on the retailer site.\n\nThis database is manually curated from different sources and is NOT automated. It only contains /cart/estimates compatible coupons, which means site-wide discounts. Product/category coupons are currently not supported.\n\nOur team is happy to accept new coupons and enter them in our database. Just email support@twotap.com.\n\nThere's no associated cost with this endpoint, all coupons are offered for free.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"Because this request requires a private token you should only perform it **server side**.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"How to parse the coupon rules.\"\n}\n[/block]\nCoupons are split into benefits and conditions. If the conditions are met you can apply the benefits. Multiple rules can be sent for one coupon in complex situations (5% off $100+, 10% off $200).\n\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Benefits\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"free_shipping\",\n    \"0-1\": \"(true/false) Free shipping\",\n    \"1-0\": \"percentage_off\",\n    \"1-1\": \"(float) Discount is a % off the subtotal\",\n    \"2-0\": \"value_off\",\n    \"2-1\": \"(float) Discount is a fixed amount from the subtotal. Uses the site's CURRENCY_FORMAT.\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Conditions\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"threshold\",\n    \"0-1\": \"(float) The subtotal has to be above this value.\\nUses the site's CURRENCY_FORMAT\",\n    \"1-0\": \"sale\",\n    \"1-1\": \"(true/false) If this discount applies to only products on sale.\",\n    \"2-0\": \"one_item\",\n    \"2-1\": \"(true/false) If this discount applies to only one item from the cart.\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]","category":"57780374ea758f0e00e6f822","createdAt":"2016-09-05T12:31:54.990Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":999,"project":"544af341a761f90800c41d50","slug":"coupons","sync_unique":"","title":"/coupons","type":"get","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

get/coupons


Body JSON

private_token:
required
string
Your Two Tap PRIVATE token.
While Two Tap applies any coupon you send during /purchase it also has a database of active coupons. The database is used at /cart/estimates in order to, well, estimate the coupon discount before actually starting the checkout on the retailer site. This database is manually curated from different sources and is NOT automated. It only contains /cart/estimates compatible coupons, which means site-wide discounts. Product/category coupons are currently not supported. Our team is happy to accept new coupons and enter them in our database. Just email support@twotap.com. There's no associated cost with this endpoint, all coupons are offered for free. [block:callout] { "type": "danger", "body": "Because this request requires a private token you should only perform it **server side**." } [/block] [block:api-header] { "type": "basic", "title": "How to parse the coupon rules." } [/block] Coupons are split into benefits and conditions. If the conditions are met you can apply the benefits. Multiple rules can be sent for one coupon in complex situations (5% off $100+, 10% off $200). [block:api-header] { "type": "basic", "title": "Benefits" } [/block] [block:parameters] { "data": { "0-0": "free_shipping", "0-1": "(true/false) Free shipping", "1-0": "percentage_off", "1-1": "(float) Discount is a % off the subtotal", "2-0": "value_off", "2-1": "(float) Discount is a fixed amount from the subtotal. Uses the site's CURRENCY_FORMAT." }, "cols": 2, "rows": 3 } [/block] [block:api-header] { "type": "basic", "title": "Conditions" } [/block] [block:parameters] { "data": { "0-0": "threshold", "0-1": "(float) The subtotal has to be above this value.\nUses the site's CURRENCY_FORMAT", "1-0": "sale", "1-1": "(true/false) If this discount applies to only products on sale.", "2-0": "one_item", "2-1": "(true/false) If this discount applies to only one item from the cart." }, "cols": 2, "rows": 3 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



While Two Tap applies any coupon you send during /purchase it also has a database of active coupons. The database is used at /cart/estimates in order to, well, estimate the coupon discount before actually starting the checkout on the retailer site. This database is manually curated from different sources and is NOT automated. It only contains /cart/estimates compatible coupons, which means site-wide discounts. Product/category coupons are currently not supported. Our team is happy to accept new coupons and enter them in our database. Just email support@twotap.com. There's no associated cost with this endpoint, all coupons are offered for free. [block:callout] { "type": "danger", "body": "Because this request requires a private token you should only perform it **server side**." } [/block] [block:api-header] { "type": "basic", "title": "How to parse the coupon rules." } [/block] Coupons are split into benefits and conditions. If the conditions are met you can apply the benefits. Multiple rules can be sent for one coupon in complex situations (5% off $100+, 10% off $200). [block:api-header] { "type": "basic", "title": "Benefits" } [/block] [block:parameters] { "data": { "0-0": "free_shipping", "0-1": "(true/false) Free shipping", "1-0": "percentage_off", "1-1": "(float) Discount is a % off the subtotal", "2-0": "value_off", "2-1": "(float) Discount is a fixed amount from the subtotal. Uses the site's CURRENCY_FORMAT." }, "cols": 2, "rows": 3 } [/block] [block:api-header] { "type": "basic", "title": "Conditions" } [/block] [block:parameters] { "data": { "0-0": "threshold", "0-1": "(float) The subtotal has to be above this value.\nUses the site's CURRENCY_FORMAT", "1-0": "sale", "1-1": "(true/false) If this discount applies to only products on sale.", "2-0": "one_item", "2-1": "(true/false) If this discount applies to only one item from the cart." }, "cols": 2, "rows": 3 } [/block]
{"category":"57780374ea758f0e00e6f823","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f834","createdAt":"2015-10-19T19:41:20.979Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":32,"body":"Two Tap has BETA support for ordering a product and picking up in store. \n\nPickup from store is enabled on demand. If you'd like us to support it for a retailer please email us at support@twotap.com.\n\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Limitations\"\n}\n[/block]\nThere are a couple of limitations:\n* It requires retailers to support pickup from store on their website.\n* It only works via the API, there is no Cart support at this time.\n* Products that are *only* pickup from store (no shipping support) can not be ordered at this time.\n* All products in a /cart need to be available for pickup.\n\nWe are working to extend this functionality in the near future.","excerpt":"","slug":"pickup-from-store","type":"basic","title":"Pickup from Store","__v":0,"childrenPages":[]}

Pickup from Store


Two Tap has BETA support for ordering a product and picking up in store. Pickup from store is enabled on demand. If you'd like us to support it for a retailer please email us at support@twotap.com. [block:api-header] { "type": "basic", "title": "Limitations" } [/block] There are a couple of limitations: * It requires retailers to support pickup from store on their website. * It only works via the API, there is no Cart support at this time. * Products that are *only* pickup from store (no shipping support) can not be ordered at this time. * All products in a /cart need to be available for pickup. We are working to extend this functionality in the near future.
Two Tap has BETA support for ordering a product and picking up in store. Pickup from store is enabled on demand. If you'd like us to support it for a retailer please email us at support@twotap.com. [block:api-header] { "type": "basic", "title": "Limitations" } [/block] There are a couple of limitations: * It requires retailers to support pickup from store on their website. * It only works via the API, there is no Cart support at this time. * Products that are *only* pickup from store (no shipping support) can not be ordered at this time. * All products in a /cart need to be available for pickup. We are working to extend this functionality in the near future.
{"category":"57780374ea758f0e00e6f823","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f835","createdAt":"2015-10-19T23:38:18.538Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":33,"body":"As mentioned above, all products in a /cart need to be able to be picked up from store. You should check that 'pickup_support' is true in the /cart/status response for all products.","excerpt":"","slug":"before-pickup_options","type":"basic","title":"Before /pickup_options","__v":0,"childrenPages":[]}

Before /pickup_options


As mentioned above, all products in a /cart need to be able to be picked up from store. You should check that 'pickup_support' is true in the /cart/status response for all products.
As mentioned above, all products in a /cart need to be able to be picked up from store. You should check that 'pickup_support' is true in the /cart/status response for all products.
{"__v":0,"_id":"57780374ea758f0e00e6f836","api":{"examples":{"codes":[{"name":"Ruby","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\ncart_id = ARGV[0]\n\nfields_input = { \n  [site_id]: {\n    \"localCheckout\" => { \"shipping_zip\" => \"94303\" },\n    \"addToCart\": {\n      [product_md5]: { \"quantity\": 1 }\n    }\n  }\n}\n\nproducts = [ 'http://fab.com/sale/4850/product/11263' ]\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/pickup_options?public_token=PUBLIC_TOKEN\", { \n  cart_id: cart_id, \n  fields_input: fields_input,\n  products: products \n}\n\nputs response.body","language":"ruby"}]},"results":{"codes":[{"name":"","code":"{\n  \"purchase_id\": \"50f414b9e6a4869bf6000010\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\"\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"562578d28a11e50d00be3d34","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"562578d28a11e50d00be3d33","ref":"","required":true,"desc":"The cart id that is sent by '/cart'.","default":"","type":"string","name":"cart_id","in":"body"},{"_id":"562578d28a11e50d00be3d32","ref":"","required":true,"desc":"A hash containing pickup information by site_id.","default":"","type":"object","name":"fields_input","in":"body"},{"_id":"562578d28a11e50d00be3d31","ref":"","required":false,"desc":"(Optional) An array of product URLs that have accepted by the user. This is useful in case an user removes some items between /cart and /purchase.  If specified fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's that you originally send us.","default":"","type":"string","name":"products","in":"body"},{"_id":"56934b48b5dc340d001c31b8","ref":"","required":false,"desc":"Optional) An endpoint where Two Tap can POST the pickup information once it has been retrieved.","default":"","type":"string","name":"finished_url","in":"body"}],"url":"/pickup_options"},"body":"Pickup Options will begin a checkout session on the retailer's end and will stop as soon as it can retrieve the available pickup stores.\n\nThis request needs to be POSTed with a shipping_zip for each site_id.\n\nThis request is processed in the background which means you have to call '/pickup_options/status'.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"The 'fields_input' parameter\"\n}\n[/block]\nThe 'fields_input' parameter is a hash that looks like below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\\"5225da1055a0f96c8b000004\\\" => {\\n  \\\"localCheckout\\\" => { \\\"shipping_zip\\\" => \\\"94303\\\" },\\n  \\\"addToCart\\\" => {\\n    \\\"82efa6ab18e09ae30893e2aa8b74b0a1\\\" => { \\\"quantity\\\" => 1 },\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Example\"\n    }\n  ]\n}\n[/block]","category":"57780374ea758f0e00e6f823","createdAt":"2015-10-19T22:25:11.286Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":34,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"pickup_options","sync_unique":"","title":"/pickup_options","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/pickup_options


Body JSON

public_token:
required
string
Your Two Tap public token.
cart_id:
required
string
The cart id that is sent by '/cart'.
fields_input:
required
object
A hash containing pickup information by site_id.
products:
string
(Optional) An array of product URLs that have accepted by the user. This is useful in case an user removes some items between /cart and /purchase. If specified fields_input should contain only the required data for those products. These are Two Tap 'url's from /cart/status, and NOT the 'original_url's that you originally send us.
finished_url:
string
Optional) An endpoint where Two Tap can POST the pickup information once it has been retrieved.
Pickup Options will begin a checkout session on the retailer's end and will stop as soon as it can retrieve the available pickup stores. This request needs to be POSTed with a shipping_zip for each site_id. This request is processed in the background which means you have to call '/pickup_options/status'. [block:api-header] { "type": "basic", "title": "The 'fields_input' parameter" } [/block] The 'fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "\"5225da1055a0f96c8b000004\" => {\n \"localCheckout\" => { \"shipping_zip\" => \"94303\" },\n \"addToCart\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => { \"quantity\" => 1 },\n }\n}", "language": "json", "name": "Example" } ] } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



Pickup Options will begin a checkout session on the retailer's end and will stop as soon as it can retrieve the available pickup stores. This request needs to be POSTed with a shipping_zip for each site_id. This request is processed in the background which means you have to call '/pickup_options/status'. [block:api-header] { "type": "basic", "title": "The 'fields_input' parameter" } [/block] The 'fields_input' parameter is a hash that looks like below: [block:code] { "codes": [ { "code": "\"5225da1055a0f96c8b000004\" => {\n \"localCheckout\" => { \"shipping_zip\" => \"94303\" },\n \"addToCart\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => { \"quantity\" => 1 },\n }\n}", "language": "json", "name": "Example" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f837","api":{"examples":{"codes":[{"name":"Ruby","code":"#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\n\npurchase_id = ARGV[0]\n\nresponse = RestClient.get \"https://api.twotap.com/v1.0/pickup_options/status?public_token=PUBLIC_TOKEN&cart_id=#{cart_id}\"\n\nputs response.body","language":"ruby"}]},"results":{"codes":[{"status":200,"language":"json","code":"{\n  \"cart_id\": \"56131fe1b88a91ba1a9b0d7a\",\n  \"message\": \"still_processing\",\n  \"description\": \"Still processing.\",\n  \"sites\": {\n    \"532603efe6a4867999000001\": {\n      \"last_message\": \"Adding product to cart\",\n      \"percent_done\": 33.53819139596137,\n      \"status\": \"still_processing\"\n    }\n  }\n}","name":"still_processing"},{"status":200,"language":"json","code":"{\n  \"sites\":{\n    \"532603efe6a4867999000001\":{\n      \"pickup_options\":{\n        \"13edbb4cf92aa22f5d454c653093945a\":[\n          {\n            \"when\":\"OCT 14 - OCT 19\",\n            \"phone\":\"\",\n            \"name\":\"Kifer Rd #640\",\n            \"distance\":\"3.70 miles away\",\n            \"address\":\"680 Kifer Rd, Sunnyvale, CA 94086 | (408)245-3686\"\n          },\n          {\n            \"when\":\"OCT 14 - OCT 19\",\n            \"phone\":\"\",\n            \"name\":\"Bollinger #6635\",\n            \"distance\":\"5.58 miles away\",\n            \"address\":\"975 De Anza Blvd, San Jose, CA 95129 | (408)253-3537\"\n          }\n        ]\n      },\n      \"status\":\"done\"\n    }\n  },\n  \"cart_id\":\"56131fe1b88a91ba1a9b0d7a\",\n  \"message\":\"done\"\n}","name":""}]},"settings":"","auth":"required","params":[{"_id":"56257cf172ac510d00e492df","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"query"},{"_id":"56257cf172ac510d00e492de","ref":"","required":true,"desc":"The cart's id.","default":"","type":"string","name":"cart_id","in":"query"}],"url":"/pickup_options/status"},"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Response description\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"cart_id\",\n    \"0-1\": \"The cart's id.\",\n    \"1-0\": \"message\",\n    \"1-1\": \"If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.\",\n    \"2-0\": \"description\",\n    \"2-1\": \"A more human-friendly description of the message.\",\n    \"3-0\": \"sites\",\n    \"3-1\": \"A hash that contains information grouped by a siteID.\",\n    \"4-0\": \"sites[id][pickup_options][productMD5][name]\",\n    \"4-1\": \"The pickup store's name.\",\n    \"5-0\": \"sites[id][pickup_options][productMD5][phone]\",\n    \"5-1\": \"Optional. The pickup store's phone number.\",\n    \"6-0\": \"sites[id][pickup_options][productMD5][when]\",\n    \"6-1\": \"Optional. When the product can be picked up at this store.\",\n    \"7-0\": \"sites[id][pickup_options][productMD5][distance]\",\n    \"7-1\": \"Optional. Distance to the store.\",\n    \"8-0\": \"sites[id][pickup_options][productMD5][address]\",\n    \"8-1\": \"Optional. Store address.\",\n    \"9-0\": \"sites[id][status]\",\n    \"9-1\": \"The status, which can be 'still_processing', 'has_failures', or 'done'.\",\n    \"10-0\": \"sites[id][last_message]\",\n    \"10-1\": \"The latest status message sent by the request processor. This is used during the 'still_processing' phase.\"\n  },\n  \"cols\": 2,\n  \"rows\": 11\n}\n[/block]","category":"57780374ea758f0e00e6f823","createdAt":"2015-10-19T23:19:29.109Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":35,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"pickup_optionsstatus","sync_unique":"","title":"/pickup_options/status","type":"get","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

get/pickup_options/status


Query Params

public_token:
required
string
Your Two Tap public token.
cart_id:
required
string
The cart's id.
[block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "cart_id", "0-1": "The cart's id.", "1-0": "message", "1-1": "If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.", "2-0": "description", "2-1": "A more human-friendly description of the message.", "3-0": "sites", "3-1": "A hash that contains information grouped by a siteID.", "4-0": "sites[id][pickup_options][productMD5][name]", "4-1": "The pickup store's name.", "5-0": "sites[id][pickup_options][productMD5][phone]", "5-1": "Optional. The pickup store's phone number.", "6-0": "sites[id][pickup_options][productMD5][when]", "6-1": "Optional. When the product can be picked up at this store.", "7-0": "sites[id][pickup_options][productMD5][distance]", "7-1": "Optional. Distance to the store.", "8-0": "sites[id][pickup_options][productMD5][address]", "8-1": "Optional. Store address.", "9-0": "sites[id][status]", "9-1": "The status, which can be 'still_processing', 'has_failures', or 'done'.", "10-0": "sites[id][last_message]", "10-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase." }, "cols": 2, "rows": 11 } [/block]

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



[block:api-header] { "type": "basic", "title": "Response description" } [/block] [block:parameters] { "data": { "0-0": "cart_id", "0-1": "The cart's id.", "1-0": "message", "1-1": "If Two Tap has completed the request: 'still_processing', 'has_failures', or 'done'.", "2-0": "description", "2-1": "A more human-friendly description of the message.", "3-0": "sites", "3-1": "A hash that contains information grouped by a siteID.", "4-0": "sites[id][pickup_options][productMD5][name]", "4-1": "The pickup store's name.", "5-0": "sites[id][pickup_options][productMD5][phone]", "5-1": "Optional. The pickup store's phone number.", "6-0": "sites[id][pickup_options][productMD5][when]", "6-1": "Optional. When the product can be picked up at this store.", "7-0": "sites[id][pickup_options][productMD5][distance]", "7-1": "Optional. Distance to the store.", "8-0": "sites[id][pickup_options][productMD5][address]", "8-1": "Optional. Store address.", "9-0": "sites[id][status]", "9-1": "The status, which can be 'still_processing', 'has_failures', or 'done'.", "10-0": "sites[id][last_message]", "10-1": "The latest status message sent by the request processor. This is used during the 'still_processing' phase." }, "cols": 2, "rows": 11 } [/block]
{"category":"57780374ea758f0e00e6f823","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f838","createdAt":"2015-10-19T23:42:50.653Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":36,"body":"At the end of /pickup_options/status you receive an array of stores. Send the store's name in the \"pickup\" hash as shown below, and use \"localCheckout\".\n\nFor more information see the /purchase API method.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#!/usr/bin/env ruby\\n\\nrequire 'rubygems'\\nrequire 'rest_client'\\nrequire 'json'\\n\\ncart_id = ARGV[0]\\n\\nrequired_fields = { \\n  \\\"5225da1055a0f96c8b000004\\\" => {\\n    \\\"localCheckout\\\" => { ... },\\n    \\\"addToCart\\\" => {\\n      \\\"82efa6ab18e09ae30893e2aa8b74b0a1\\\" => { \\\"quantity\\\" => 1 },\\n    },\\n    \\\"pickup\\\" => {\\n      \\\"82efa6ab18e09ae30893e2aa8b74b0a1\\\" => \\\"__STORE_NAME__\\\",\\n    }\\n  }\\n}\\n\\nresponse = RestClient.post \\\"https://api.twotap.com/v1.0/purchase?public_token=9aad34ed6833a78b268f572a2cb182\\\", { :cart_id => cart_id, :fields_input => required_fields }\\n\\nputs response.body\",\n      \"language\": \"ruby\",\n      \"name\": \"Ruby\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"after-pickup_support","type":"basic","title":"After /pickup_support","__v":0,"childrenPages":[]}

After /pickup_support


At the end of /pickup_options/status you receive an array of stores. Send the store's name in the "pickup" hash as shown below, and use "localCheckout". For more information see the /purchase API method. [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\nrequire 'json'\n\ncart_id = ARGV[0]\n\nrequired_fields = { \n \"5225da1055a0f96c8b000004\" => {\n \"localCheckout\" => { ... },\n \"addToCart\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => { \"quantity\" => 1 },\n },\n \"pickup\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => \"__STORE_NAME__\",\n }\n }\n}\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=9aad34ed6833a78b268f572a2cb182\", { :cart_id => cart_id, :fields_input => required_fields }\n\nputs response.body", "language": "ruby", "name": "Ruby" } ] } [/block]
At the end of /pickup_options/status you receive an array of stores. Send the store's name in the "pickup" hash as shown below, and use "localCheckout". For more information see the /purchase API method. [block:code] { "codes": [ { "code": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rest_client'\nrequire 'json'\n\ncart_id = ARGV[0]\n\nrequired_fields = { \n \"5225da1055a0f96c8b000004\" => {\n \"localCheckout\" => { ... },\n \"addToCart\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => { \"quantity\" => 1 },\n },\n \"pickup\" => {\n \"82efa6ab18e09ae30893e2aa8b74b0a1\" => \"__STORE_NAME__\",\n }\n }\n}\n\nresponse = RestClient.post \"https://api.twotap.com/v1.0/purchase?public_token=9aad34ed6833a78b268f572a2cb182\", { :cart_id => cart_id, :fields_input => required_fields }\n\nputs response.body", "language": "ruby", "name": "Ruby" } ] } [/block]
{"category":"57780374ea758f0e00e6f824","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f84a","createdAt":"2015-07-10T20:40:15.257Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":37,"body":"The wallet allows users and publishers to store data with Two Tap and use them for purchases. The retrieving and storing of data is integrated into the '/cart' and '/purchase' requests if 'user_token' is sent as a parameter.\n\nThere are three ways of enabling a wallet inside your app.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Shared wallet\"\n}\n[/block]\nWith the shared wallet, apps agree that if a shopper enters her information in one app it should be available in any other app that implements the shared wallet. This is similar to how Visa Checkout or Masterpass works.\n\nThe shared wallet requires a two-factor SMS flow on the consumer side.\n\nIn order to implement the shared wallet you have to [contact us](https://twotap.com/contact).\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Private wallet\"\n}\n[/block]\nSome publishers prefer to have their own private wallet and avoid the shared one because of the SMS authentication. Information about this integration type is available below under /wallet/user_token.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Advanced private wallet\"\n}\n[/block]\nIf you're looking for a more advanced wallet that allows you to connect to both Two Tap and payment processors at the same time Two Tap has partnered with [Spreedly](https://spreedly.com/).","excerpt":"","slug":"the-wallet","type":"basic","title":"The Wallet","__v":0,"childrenPages":[]}

The Wallet


The wallet allows users and publishers to store data with Two Tap and use them for purchases. The retrieving and storing of data is integrated into the '/cart' and '/purchase' requests if 'user_token' is sent as a parameter. There are three ways of enabling a wallet inside your app. [block:api-header] { "type": "basic", "title": "Shared wallet" } [/block] With the shared wallet, apps agree that if a shopper enters her information in one app it should be available in any other app that implements the shared wallet. This is similar to how Visa Checkout or Masterpass works. The shared wallet requires a two-factor SMS flow on the consumer side. In order to implement the shared wallet you have to [contact us](https://twotap.com/contact). [block:api-header] { "type": "basic", "title": "Private wallet" } [/block] Some publishers prefer to have their own private wallet and avoid the shared one because of the SMS authentication. Information about this integration type is available below under /wallet/user_token. [block:api-header] { "type": "basic", "title": "Advanced private wallet" } [/block] If you're looking for a more advanced wallet that allows you to connect to both Two Tap and payment processors at the same time Two Tap has partnered with [Spreedly](https://spreedly.com/).
The wallet allows users and publishers to store data with Two Tap and use them for purchases. The retrieving and storing of data is integrated into the '/cart' and '/purchase' requests if 'user_token' is sent as a parameter. There are three ways of enabling a wallet inside your app. [block:api-header] { "type": "basic", "title": "Shared wallet" } [/block] With the shared wallet, apps agree that if a shopper enters her information in one app it should be available in any other app that implements the shared wallet. This is similar to how Visa Checkout or Masterpass works. The shared wallet requires a two-factor SMS flow on the consumer side. In order to implement the shared wallet you have to [contact us](https://twotap.com/contact). [block:api-header] { "type": "basic", "title": "Private wallet" } [/block] Some publishers prefer to have their own private wallet and avoid the shared one because of the SMS authentication. Information about this integration type is available below under /wallet/user_token. [block:api-header] { "type": "basic", "title": "Advanced private wallet" } [/block] If you're looking for a more advanced wallet that allows you to connect to both Two Tap and payment processors at the same time Two Tap has partnered with [Spreedly](https://spreedly.com/).
{"__v":0,"_id":"57780374ea758f0e00e6f84b","api":{"examples":{"codes":[{"name":"","code":"response = RestClient.post \"https://api.twotap.com/v1.0/wallet/user_token?private_token=PRIVATE_TOKEN\", { \n  user_key: \"user@user.com\",\n}","language":"ruby"}]},"results":{"codes":[{"name":"","code":"{ \n  message: \"done\",\n  user_token: \"p_ZPSMDvaWDrHl2BoAfAqMveCAIImZfalx\"\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a335664055c62300d2b197","ref":"","required":true,"desc":"Your Two Tap PRIVATE token.","default":"","type":"string","name":"private_token","in":"body"},{"_id":"55a335b24055c62300d2b19b","ref":"","required":true,"desc":"A key to identify the user by. Usually this is the shopper's email address.","default":"","type":"string","name":"user_key","in":"body"}],"url":"/wallet/user_token"},"body":"This method allows you to get a user_token for Two Tap's **private wallet**. Send a user_key, which is usually the email address, and Two Tap will send back a user_token associated with that user_key that you can use with the other /wallet endpoints.\n\nSince this request requires a private token make sure you call it server-side.","category":"57780374ea758f0e00e6f824","createdAt":"2016-01-30T06:48:07.237Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":38,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"wallet-user-token","sync_unique":"","title":"/wallet/user_token","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/wallet/user_token


Body JSON

private_token:
required
string
Your Two Tap PRIVATE token.
user_key:
required
string
A key to identify the user by. Usually this is the shopper's email address.
This method allows you to get a user_token for Two Tap's **private wallet**. Send a user_key, which is usually the email address, and Two Tap will send back a user_token associated with that user_key that you can use with the other /wallet endpoints. Since this request requires a private token make sure you call it server-side.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



This method allows you to get a user_token for Two Tap's **private wallet**. Send a user_key, which is usually the email address, and Two Tap will send back a user_token associated with that user_key that you can use with the other /wallet endpoints. Since this request requires a private token make sure you call it server-side.
{"category":"57780374ea758f0e00e6f824","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f84c","createdAt":"2015-07-10T20:39:42.263Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":39,"body":"Storing of data is done automatically during '/purchase' if a 'user_token' is supplied.","excerpt":"","slug":"storing-data-purchase","type":"basic","title":"Storing data (/purchase)","__v":0,"childrenPages":[]}

Storing data (/purchase)


Storing of data is done automatically during '/purchase' if a 'user_token' is supplied.
Storing of data is done automatically during '/purchase' if a 'user_token' is supplied.
{"category":"57780374ea758f0e00e6f824","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f84d","createdAt":"2015-07-10T20:41:38.449Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":40,"body":"When posting a request to '/cart' if a 'user_token' is present the API will respond with the stored entries for the required fields.\n\nThe stored fields are grouped in three possible categories: 'shipping', 'payment', and 'login'. The user can store multiple shipping addresses, payment methods, and login credentials which are grouped together.\n\nThe 'shipping' and 'payment' groups are identified by a random id. 'login' groups are identified by the site_id they belong to.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Wallet Retrieval\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"# Similar to a regular '/cart' request however an 'user_token' is specified.\\nresponse = RestClient.post \\\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\\\", { \\n  products: products, \\n  user_token: USER_TOKEN \\n}\\n\\n# Completed Status Response\\n{\\n  \\\"sites\\\": {\\n    # ...\\n  },\\n  \\\"stored_field_values\\\": {\\n    \\\"shipping\\\": {\\n      \\\"o6nfusor\\\": {\\n        \\\"data\\\": {\\n          \\\"email\\\": {\\n            \\\"text\\\": \\\"anemail@gmail.com\\\"\\n          },\\n          \\\"shipping_last_name\\\": {\\n            \\\"text\\\": \\\"Doe\\\"\\n          },\\n          \\\"shipping_first_name\\\": {\\n            \\\"text\\\": \\\"Joe\\\"\\n          }\\n        },\\n        \\\"name\\\": \\\"John, Doe, anemail@gmail.com\\\"\\n      }\\n    },\\n    \\\"login\\\": {\\n      \\\"50f414b9e6a4869bf6000002\\\": {\\n        \\\"data\\\": {\\n          \\\"email\\\": {\\n            \\\"text\\\": \\\"anuser@gmail.com\\\"\\n          }\\n        },\\n        \\\"name\\\": \\\"anuser@gmail.com\\\"\\n      }\\n    }\\n  },\\n  # ...\\n}\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"#!/bin/bash\\n\\nPUBLIC_TOKEN=PUBLIC_TOKEN\\n\\ncurl https://api.twotap.com/v1.0/cart?public_token=$PUBLIC_TOKEN --header 'Content-Type: application/json' --data-binary '{\\n  \\\"products\\\": PRODUCTS,\\n  \\\"user_token\\\": USER_TOKEN\\n}'\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"#!/usr/bin/python\\n\\nimport requests\\nimport json\\n\\npayload = {\\n  \\\"products\\\": \\\"PRODUCTS\\\",\\n  \\\"user_token\\\": \\\"USER_TOKEN\\\"\\n}\\n\\nr = requests.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN',\\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\\n\\nprint(r.json())\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"$.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN', {\\n  \\\"products\\\": PRODUCTS, \\\"user_token\\\": USER_TOKEN\\n}, function(data, status) {\\n    console.log(data);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"var request = require(\\\"request\\\");\\nrequest({\\n    url: 'https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN'\\n    json: {\\\"products\\\": PRODUCTS, \\\"user_token\\\": USER_TOKEN},\\n    method: \\\"POST\\\"\\n}, function (err, reponse, body) {\\n    console.log(body); \\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"<?php\\nrequire_once 'Requests/library/Requests.php';\\n\\nRequests::register_autoloader();\\n$url = \\\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\\\";\\n$payload = array(\\\"products\\\" => PRODUCTS, \\\"user_token\\\" => USER_TOKEN);\\n$response = Requests::post($url, array(), $payload);\\necho $response->body;\\n?>\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"package main\\n\\nimport (\\n  \\\"fmt\\\"\\n  \\\"net/http\\\"\\n  \\\"io/ioutil\\\"\\n  \\\"bytes\\\"\\n)\\n\\nfunc main() {\\n    url := \\\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\\\"\\n    var jsonStr = []byte(`{\\\"products\\\": PRODUCTS, \\\"user_token\\\": USER_TOKEN}`)\\n    req, err := http.NewRequest(\\\"POST\\\", url, bytes.NewBuffer(jsonStr))\\n    client := &http.Client{}\\n    resp, err := client.Do(req)\\n    if err != nil {\\n        panic(err)\\n    }\\n    defer resp.Body.Close()\\n    body, _ := ioutil.ReadAll(resp.Body)\\n    fmt.Println(string(body))\\n}\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"using System;\\nusing System.Collections.Generic;\\nusing System.Net.Http;\\nusing System.Net.Http.Headers;\\nusing System.Dynamic;\\nusing System.Text;\\nusing Newtonsoft.Json;\\n\\npublic class EmptyClass\\n{\\n  public static void Main ()\\n  {\\n    using (var client = new HttpClient ()) {\\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\\\"application/json\\\"));\\n      client.BaseAddress = new Uri (\\\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\\\");\\n      dynamic payload = new ExpandoObject ();\\n      payload.products = \\\"PRODUCTS\\\";\\n      payload.user_token = \\\"USER_TOKEN\\\";\\n      string json = JsonConvert.SerializeObject(payload);\\n      var result = client.PostAsync (\\\"\\\", new StringContent(json, Encoding.UTF8, \\\"application/json\\\")).Result;\\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\\n      Console.WriteLine (resultContent);\\n    }\\n  }\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"retrieving-data-cart","type":"basic","title":"Retrieving data (/cart)","__v":0,"childrenPages":[]}

Retrieving data (/cart)


When posting a request to '/cart' if a 'user_token' is present the API will respond with the stored entries for the required fields. The stored fields are grouped in three possible categories: 'shipping', 'payment', and 'login'. The user can store multiple shipping addresses, payment methods, and login credentials which are grouped together. The 'shipping' and 'payment' groups are identified by a random id. 'login' groups are identified by the site_id they belong to. [block:api-header] { "type": "basic", "title": "Wallet Retrieval" } [/block] [block:code] { "codes": [ { "code": "# Similar to a regular '/cart' request however an 'user_token' is specified.\nresponse = RestClient.post \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\", { \n products: products, \n user_token: USER_TOKEN \n}\n\n# Completed Status Response\n{\n \"sites\": {\n # ...\n },\n \"stored_field_values\": {\n \"shipping\": {\n \"o6nfusor\": {\n \"data\": {\n \"email\": {\n \"text\": \"anemail@gmail.com\"\n },\n \"shipping_last_name\": {\n \"text\": \"Doe\"\n },\n \"shipping_first_name\": {\n \"text\": \"Joe\"\n }\n },\n \"name\": \"John, Doe, anemail@gmail.com\"\n }\n },\n \"login\": {\n \"50f414b9e6a4869bf6000002\": {\n \"data\": {\n \"email\": {\n \"text\": \"anuser@gmail.com\"\n }\n },\n \"name\": \"anuser@gmail.com\"\n }\n }\n },\n # ...\n}", "language": "ruby" }, { "code": "#!/bin/bash\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\n\ncurl https://api.twotap.com/v1.0/cart?public_token=$PUBLIC_TOKEN --header 'Content-Type: application/json' --data-binary '{\n \"products\": PRODUCTS,\n \"user_token\": USER_TOKEN\n}'", "language": "curl" }, { "code": "#!/usr/bin/python\n\nimport requests\nimport json\n\npayload = {\n \"products\": \"PRODUCTS\",\n \"user_token\": \"USER_TOKEN\"\n}\n\nr = requests.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN',\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(r.json())", "language": "python" }, { "code": "$.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN', {\n \"products\": PRODUCTS, \"user_token\": USER_TOKEN\n}, function(data, status) {\n console.log(data);\n});", "language": "javascript" }, { "code": "var request = require(\"request\");\nrequest({\n url: 'https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN'\n json: {\"products\": PRODUCTS, \"user_token\": USER_TOKEN},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\";\n$payload = array(\"products\" => PRODUCTS, \"user_token\" => USER_TOKEN);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n url := \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\"\n var jsonStr = []byte(`{\"products\": PRODUCTS, \"user_token\": USER_TOKEN}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\");\n dynamic payload = new ExpandoObject ();\n payload.products = \"PRODUCTS\";\n payload.user_token = \"USER_TOKEN\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block]
When posting a request to '/cart' if a 'user_token' is present the API will respond with the stored entries for the required fields. The stored fields are grouped in three possible categories: 'shipping', 'payment', and 'login'. The user can store multiple shipping addresses, payment methods, and login credentials which are grouped together. The 'shipping' and 'payment' groups are identified by a random id. 'login' groups are identified by the site_id they belong to. [block:api-header] { "type": "basic", "title": "Wallet Retrieval" } [/block] [block:code] { "codes": [ { "code": "# Similar to a regular '/cart' request however an 'user_token' is specified.\nresponse = RestClient.post \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\", { \n products: products, \n user_token: USER_TOKEN \n}\n\n# Completed Status Response\n{\n \"sites\": {\n # ...\n },\n \"stored_field_values\": {\n \"shipping\": {\n \"o6nfusor\": {\n \"data\": {\n \"email\": {\n \"text\": \"anemail@gmail.com\"\n },\n \"shipping_last_name\": {\n \"text\": \"Doe\"\n },\n \"shipping_first_name\": {\n \"text\": \"Joe\"\n }\n },\n \"name\": \"John, Doe, anemail@gmail.com\"\n }\n },\n \"login\": {\n \"50f414b9e6a4869bf6000002\": {\n \"data\": {\n \"email\": {\n \"text\": \"anuser@gmail.com\"\n }\n },\n \"name\": \"anuser@gmail.com\"\n }\n }\n },\n # ...\n}", "language": "ruby" }, { "code": "#!/bin/bash\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\n\ncurl https://api.twotap.com/v1.0/cart?public_token=$PUBLIC_TOKEN --header 'Content-Type: application/json' --data-binary '{\n \"products\": PRODUCTS,\n \"user_token\": USER_TOKEN\n}'", "language": "curl" }, { "code": "#!/usr/bin/python\n\nimport requests\nimport json\n\npayload = {\n \"products\": \"PRODUCTS\",\n \"user_token\": \"USER_TOKEN\"\n}\n\nr = requests.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN',\n data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(r.json())", "language": "python" }, { "code": "$.post('https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN', {\n \"products\": PRODUCTS, \"user_token\": USER_TOKEN\n}, function(data, status) {\n console.log(data);\n});", "language": "javascript" }, { "code": "var request = require(\"request\");\nrequest({\n url: 'https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN'\n json: {\"products\": PRODUCTS, \"user_token\": USER_TOKEN},\n method: \"POST\"\n}, function (err, reponse, body) {\n console.log(body); \n});", "language": "javascript", "name": "Node.js" }, { "code": "<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\";\n$payload = array(\"products\" => PRODUCTS, \"user_token\" => USER_TOKEN);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>", "language": "php" }, { "code": "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n \"io/ioutil\"\n \"bytes\"\n)\n\nfunc main() {\n url := \"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\"\n var jsonStr = []byte(`{\"products\": PRODUCTS, \"user_token\": USER_TOKEN}`)\n req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n client := &http.Client{}\n resp, err := client.Do(req)\n if err != nil {\n panic(err)\n }\n defer resp.Body.Close()\n body, _ := ioutil.ReadAll(resp.Body)\n fmt.Println(string(body))\n}", "language": "go" }, { "code": "using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n public static void Main ()\n {\n using (var client = new HttpClient ()) {\n client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/cart?public_token=PUBLIC_TOKEN\");\n dynamic payload = new ExpandoObject ();\n payload.products = \"PRODUCTS\";\n payload.user_token = \"USER_TOKEN\";\n string json = JsonConvert.SerializeObject(payload);\n var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n String resultContent = result.Content.ReadAsStringAsync ().Result;\n Console.WriteLine (resultContent);\n }\n }\n}", "language": "csharp" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f84e","api":{"examples":{"codes":[{"name":"","code":"response = RestClient.post \"https://api.twotap.com/v1.0/wallet/retrieve?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\", { \n  filter_field_types: [ \"shipping\" ],\n  group_id: [ \"xvv4pldi\" ]\n}\n","language":"ruby"}]},"results":{"codes":[{"name":"","code":"{ \n  message: \"done\",\n  stored_field_values:\n    \"xvv4pldi\": {\n      \"data\": {\n        \"email\": {\n          \"text\": \"anemail@gmail.com\"\n        },\n        \"shipping_last_name\": {\n          \"text\": \"My new last name\"\n        },\n        \"shipping_first_name\": {\n          \"text\": \"My new first name\"\n        }\n      },\n      \"name\": \"My new first name, My new last name, anemail@gmail.com\"\n    }\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a335664055c62300d2b197","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"564cf23bef87aa1700107acc","ref":"","required":true,"desc":"Contact Two Tap to learn how to retrieve the user token.","default":"","type":"string","name":"user_token","in":"body"},{"_id":"55a335b24055c62300d2b19b","ref":"","required":false,"desc":"(Optional) Limit to 'shipping' or 'payment', or both.","default":"","type":"array_string","name":"filter_field_types","in":"body"},{"_id":"55a335b24055c62300d2b19a","ref":"","required":false,"desc":"(Optional) Only return certain group ids.","default":"","type":"array_string","name":"filter_group_ids","in":"body"}],"url":"/wallet/retrieve"},"body":"You can also retrieve data independently of /cart.","category":"57780374ea758f0e00e6f824","createdAt":"2016-05-30T23:00:13.543Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":41,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"wallet-retrieve","sync_unique":"","title":"/wallet/retrieve","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/wallet/retrieve


Body JSON

public_token:
required
string
Your Two Tap public token.
user_token:
required
string
Contact Two Tap to learn how to retrieve the user token.
filter_field_types:
array of strings
(Optional) Limit to 'shipping' or 'payment', or both.
filter_group_ids:
array of strings
(Optional) Only return certain group ids.
You can also retrieve data independently of /cart.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



You can also retrieve data independently of /cart.
{"category":"57780374ea758f0e00e6f824","parentDoc":null,"project":"544af341a761f90800c41d50","user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","updates":[],"_id":"57780374ea758f0e00e6f84f","createdAt":"2015-07-10T20:48:33.127Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":42,"body":"Each 'shipping', 'payment', and 'login' groups have an id associated with it. These fields are used during '/purchase'.\n\nInstead of adding the key=value pairs to the required field values just use 'shipping_group_id', 'payment_group_id', or 'login_group_id' with the associated value.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Wallet Usage\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// During a /purchase request.\\nrequired_fields = { \\n  \\\"516dece5e6a4862049000001\\\": {\\n    \\\"noauthCheckout\\\": { \\n      \\\"shipping_group_id\\\": \\\"xvv4pldi\\\",  \\n      \\\"payment_group_id\\\": \\\"frx2d9d\\\", \\n      \\\"an_extra_required_field\\\": \\\"has this value\\\" }, \\n    \\\"addToCart\\\": {\\n      \\\"6e69ada944a4c35bb320615b827ad60a\\\": { \\n        \\\"quantity\\\": 1, \\n        \\\"Size\\\": \\\"13233550|13442751\\\", \\\"Color\\\": \\n        \\\"13233550|1055745\\\" }\\n    }\\n  }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"using-data-purchase","type":"basic","title":"Using data (/purchase)","__v":0,"childrenPages":[]}

Using data (/purchase)


Each 'shipping', 'payment', and 'login' groups have an id associated with it. These fields are used during '/purchase'. Instead of adding the key=value pairs to the required field values just use 'shipping_group_id', 'payment_group_id', or 'login_group_id' with the associated value. [block:api-header] { "type": "basic", "title": "Wallet Usage" } [/block] [block:code] { "codes": [ { "code": "// During a /purchase request.\nrequired_fields = { \n \"516dece5e6a4862049000001\": {\n \"noauthCheckout\": { \n \"shipping_group_id\": \"xvv4pldi\", \n \"payment_group_id\": \"frx2d9d\", \n \"an_extra_required_field\": \"has this value\" }, \n \"addToCart\": {\n \"6e69ada944a4c35bb320615b827ad60a\": { \n \"quantity\": 1, \n \"Size\": \"13233550|13442751\", \"Color\": \n \"13233550|1055745\" }\n }\n }\n}", "language": "json" } ] } [/block]
Each 'shipping', 'payment', and 'login' groups have an id associated with it. These fields are used during '/purchase'. Instead of adding the key=value pairs to the required field values just use 'shipping_group_id', 'payment_group_id', or 'login_group_id' with the associated value. [block:api-header] { "type": "basic", "title": "Wallet Usage" } [/block] [block:code] { "codes": [ { "code": "// During a /purchase request.\nrequired_fields = { \n \"516dece5e6a4862049000001\": {\n \"noauthCheckout\": { \n \"shipping_group_id\": \"xvv4pldi\", \n \"payment_group_id\": \"frx2d9d\", \n \"an_extra_required_field\": \"has this value\" }, \n \"addToCart\": {\n \"6e69ada944a4c35bb320615b827ad60a\": { \n \"quantity\": 1, \n \"Size\": \"13233550|13442751\", \"Color\": \n \"13233550|1055745\" }\n }\n }\n}", "language": "json" } ] } [/block]
{"__v":0,"_id":"57780374ea758f0e00e6f850","api":{"examples":{"codes":[{"name":"","code":"response = RestClient.post \"https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\", { \n  field_type: \"shipping\",\n  group_id: \"xvv4pldi (optional, only if you are updating an existing group_id)\",\n  fields: { \n    shipping_first_name: \"My new first name\",\n    shipping_last_name: \"My new last name\"\n  }\n}\n","language":"ruby"},{"code":"#!/bin/bash\n\nPUBLIC_TOKEN=PUBLIC_TOKEN\n\ncurl https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN --header 'Content-Type: application/json' --data-binary '{ \n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi (optional)\",\n  \"fields\": { \n    \"shipping_first_name\": \"My new first name\",\n    \"shipping_last_name\": \"My new last name\"\n  }\n}'","language":"curl"},{"code":"#!/usr/bin/python\n\nimport requests\nimport json\n\npayload = { \n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi (optional)\",\n  \"fields\": { \n    \"shipping_first_name\": \"My new first name\",\n    \"shipping_last_name\": \"My new last name\"\n  }\n}\n\nr = requests.post('https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN',\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\n\nprint(r.json())","language":"python"},{"code":"$.post('https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN', {\n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi (optional)\",\n  \"fields\": { \n    \"shipping_first_name\": \"My new first name\",\n    \"shipping_last_name\": \"My new last name\"\n  }\n}, function(data, status) {\n    console.log(data);\n});","language":"javascript"},{"code":"var request = require(\"request\");\nrequest({\n    url: 'https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN'\n    json: { \n    \"field_type\": \"shipping\",\n    \"field_group_id\": \"xvv4pldi (optional)\",\n    \"fields\": { \n      \"shipping_first_name\": \"My new first name\",\n      \"shipping_last_name\": \"My new last name\"\n    }\n  },\n    method: \"POST\"\n}, function (err, reponse, body) {\n    console.log(body); \n});","language":"javascript","name":"Node.js"},{"code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = \"https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\";\n$payload = array( \n  \"field_type\" => \"shipping\",\n  \"field_group_id\" => \"xvv4pldi (optional)\",\n  \"fields\" => array( \n    \"shipping_first_name\" => \"My new first name\",\n    \"shipping_last_name\" => \"My new last name\"\n  )\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>","language":"php"},{"code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    url := \"https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\"\n    var jsonStr = []byte(`{ \n      \"field_type\": \"shipping\",\n      \"field_group_id:\" \"xvv4pldi (optional)\",\n      \"fields\": { \n        \"shipping_first_name\": \"My new first name\",\n        \"shipping_last_name\": \"My new last name\"\n      }\n    }`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}","language":"go"},{"code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/wallet/store?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\");\n      dynamic payload = new ExpandoObject ();\n      payload.field_type = \"shipping\";\n      payload.field_group_id = \"xvv4pldi (optional)\";\n      payload.fields = new ExpandoObject ();\n      payload.fields.shipping_first_name = \"My new first name\";\n      payload.shipping_last_name = \"My new last name\";\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}","language":"csharp"}]},"results":{"codes":[{"name":"","code":"{ \n  message: \"done\",\n  stored_field_values:\n    \"xvv4pldi\": {\n      \"data\": {\n        \"email\": {\n          \"text\": \"anemail@gmail.com\"\n        },\n        \"shipping_last_name\": {\n          \"text\": \"My new last name\"\n        },\n        \"shipping_first_name\": {\n          \"text\": \"My new first name\"\n        }\n      },\n      \"name\": \"My new first name, My new last name, anemail@gmail.com\"\n    }\n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a335664055c62300d2b197","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"564cf23bef87aa1700107acc","ref":"","required":true,"desc":"Contact Two Tap to learn how to retrieve the user token.","default":"","type":"string","name":"user_token","in":"body"},{"_id":"55a335b24055c62300d2b19b","ref":"","required":true,"desc":"'shipping' or 'payment'","default":"","type":"string","name":"field_type","in":"body"},{"_id":"55a335b24055c62300d2b19a","ref":"","required":false,"desc":"(Optional) If you want to update an existing group.","default":"","type":"string","name":"group_id","in":"body"},{"_id":"55a335b24055c62300d2b199","ref":"","required":true,"desc":"The hash contains the information to store in the wallet. Only strings are accepted as the object values.","default":"","type":"object","name":"fields","in":"body"}],"url":"/wallet/store"},"body":"To create a new entry only send a field_type and a list of fields. Two Tap will automatically generate a group_id.\n\nIf you'd like to update an existing group also send a specific group_id.","category":"57780374ea758f0e00e6f824","createdAt":"2015-07-10T20:49:54.244Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":43,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"wallet-store","sync_unique":"","title":"/wallet/store","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/wallet/store


Body JSON

public_token:
required
string
Your Two Tap public token.
user_token:
required
string
Contact Two Tap to learn how to retrieve the user token.
field_type:
required
string
'shipping' or 'payment'
group_id:
string
(Optional) If you want to update an existing group.
fields:
required
object
The hash contains the information to store in the wallet. Only strings are accepted as the object values.
To create a new entry only send a field_type and a list of fields. Two Tap will automatically generate a group_id. If you'd like to update an existing group also send a specific group_id.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



To create a new entry only send a field_type and a list of fields. Two Tap will automatically generate a group_id. If you'd like to update an existing group also send a specific group_id.
{"__v":0,"_id":"57780374ea758f0e00e6f851","api":{"examples":{"codes":[{"language":"ruby","code":"response = RestClient.post \"https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\", { \n  field_type: \"shipping\",\n  group_id: \"xvv4pldi\"\n}","name":""},{"language":"curl","code":"#!/bin/bash\n\ncurl https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN --header 'Content-Type: application/json' --data-binary '{\n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi\"\n}'"},{"language":"python","code":"#!/usr/bin/python\n\nimport requests\nimport json\n\npayload = { \n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi\"\n}\n\nr = requests.post('https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN',\n  data=json.dumps(payload), headers={'Content-Type': 'application/json'})\nprint(r.json())"},{"language":"javascript","code":"$.post('https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN', {\n  \"field_type\": \"shipping\",\n  \"field_group_id\": \"xvv4pldi\"\n}, function(data, status) {\n    console.log(data);\n});"},{"name":"Node.js","language":"javascript","code":"var request = require(\"request\");\nrequest({\n  url: 'https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN'\n    json: { \n      \"field_type\": \"shipping\",\n      \"field_group_id\": \"xvv4pldi\"\n    },\n    method: \"POST\"\n}, function (err, reponse, body) {\n    console.log(body); \n});"},{"language":"php","code":"<?php\nrequire_once 'Requests/library/Requests.php';\n\nRequests::register_autoloader();\n$url = \"https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\";\n$payload = array( \n  \"field_type\" => \"shipping\",\n  \"field_group_id\" => \"xvv4pldi\"\n);\n$response = Requests::post($url, array(), $payload);\necho $response->body;\n?>"},{"language":"go","code":"package main\n\nimport (\n  \"fmt\"\n  \"net/http\"\n  \"io/ioutil\"\n  \"bytes\"\n)\n\nfunc main() {\n    url := \"https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\"\n    var jsonStr = []byte(`{ \n      \"field_type\": \"shipping\",\n      \"field_group_id\": \"xvv4pldi\"\n    }`)\n    req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonStr))\n    client := &http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n    body, _ := ioutil.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}"},{"language":"csharp","code":"using System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Dynamic;\nusing System.Text;\nusing Newtonsoft.Json;\n\npublic class EmptyClass\n{\n  public static void Main ()\n  {\n    using (var client = new HttpClient ()) {\n      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n      client.BaseAddress = new Uri (\"https://api.twotap.com/v1.0/wallet/delete?public_token=PUBLIC_TOKEN&user_token=USER_TOKEN\");\n      dynamic payload = new ExpandoObject ();\n      payload.field_type = \"shipping\";\n      payload.field_group_id = \"xvv4pldi\";\n      string json = JsonConvert.SerializeObject(payload);\n      var result = client.PostAsync (\"\", new StringContent(json, Encoding.UTF8, \"application/json\")).Result;\n      String resultContent = result.Content.ReadAsStringAsync ().Result;\n      Console.WriteLine (resultContent);\n    }\n  }\n}"}]},"results":{"codes":[{"name":"","code":"{ \n  message: \"done\", \n  group_id: \"xvv4pldi\" \n}","language":"json","status":200}]},"settings":"","auth":"required","params":[{"_id":"55a3363d912a6e2300882ad1","ref":"","required":true,"desc":"Your Two Tap public token.","default":"","type":"string","name":"public_token","in":"body"},{"_id":"564cf2524567342100ad967b","ref":"","required":true,"desc":"Contact Two Tap to learn how to retrieve the user token.","default":"","type":"string","name":"user_token","in":"body"},{"_id":"55a33655536110170043857d","ref":"","required":true,"desc":"'shipping' or 'payment'","default":"","type":"string","name":"field_type","in":"body"},{"_id":"55a33655536110170043857c","ref":"","required":true,"desc":"The group id you want to delete.","default":"","type":"string","name":"field_group_id","in":"body"}],"url":"/wallet/delete"},"body":"To delete an entry from the wallet all you have to do is send a field_type and a field_group_id.","category":"57780374ea758f0e00e6f824","createdAt":"2015-07-10T20:53:20.354Z","editedParams":true,"editedParams2":true,"excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":44,"parentDoc":null,"project":"544af341a761f90800c41d50","slug":"wallet-delete","sync_unique":"","title":"/wallet/delete","type":"post","updates":[],"user":"544af335a761f90800c41d4f","version":"57780374ea758f0e00e6f81d","childrenPages":[]}

post/wallet/delete


Body JSON

public_token:
required
string
Your Two Tap public token.
user_token:
required
string
Contact Two Tap to learn how to retrieve the user token.
field_type:
required
string
'shipping' or 'payment'
field_group_id:
required
string
The group id you want to delete.
To delete an entry from the wallet all you have to do is send a field_type and a field_group_id.

Definition

{{ api_url }}{{ page_api_url }}

Examples


Result Format



To delete an entry from the wallet all you have to do is send a field_type and a field_group_id.