· 4 years ago · Aug 09, 2021, 03:38 PM
1{
2 "openapi": "3.0.0",
3 "info": {
4 "title": "Versapay Ecommerce API",
5 "description": "# Table of Contents\n\n1. [Introduction](#introduction)\n2. [Server-Side Setup](#serversetup)\n3. [Client-side SDK](#client)\n4. [Server-side Orders and Payments](#serverpayments)\n\n# Introduction <a name=\"introduction\"></a>\n\nThe Versapay e-commerce solution is composed of several components. First, is a server-side API that allows your applicaiton to configure a new payment session, manage customer wallets, create orders, and initiate payments. In addition, there is a client-side JavaScript SDK that enables your web applicaiton to accept secure payment data via an iframe hosted by Versapay. Your sensitive payment data will not transit your applicaiton when you use the iframe, so your applicaiton will have a reduced PCI scope.\n\nIn order to accept a payment, the general flow is to first create a session using the server-side API. Once a session ID has been generated by the Versapay server and returned to your application, your client-side code can use that session ID to initialize the Versapay payment SDK, which will, in turn, render the iframe. Next, the customer will interact with the iframe to specify a payment method. The SDK will return a token representing that payment method to your client-side code. Your client-side code must return the token to your server-side code, which will then use the original session ID and the token to create an order and take a payment. Finally, your ERP or order fulfillment system will query the Versapay cloud platform for new orders so that they may be created and fulfilled via your standard workflow.\n\n# Server-side Setup <a name=\"serversetup\"></a>\n\n## Wallets\n\nIf the customer checking out through your website is a known customer with an authenticated account and you would like the Versapay cloud platform to offer to store payment methods for future use, you can generate a Wallet ID for that customer. To do so, POST to the `/wallets` endpoint to generate a new Wallet ID. Once the Wallet ID has been returned to your application, it is your application's responsibility to associate the Wallet ID with the customer record in your web application so that it can be provided to the API each time the customer checks out.\n\nIf the customer already has a Wallet ID associated with their record in your applicaiton, that Wallet ID should be provided in the session creation request.\n\n## Sessions\n\nEach checkout attempt requires that your application request a Session ID from the Versapay API. This is accomplished by POSTing to the `/sessions` endpoint. When creating a new session, you must specify your Versapay gateway credentials, which consist of an API Token and an API Key. These are passed in the `gatewayAuthorization` element. In addition, you may pass session options to the API that control the style, behavior, and verbiage of the iframe.\n\nSession options also allow you to specify a Wallet ID for the current customer in the `wallet` element. \n\nThe POST request to the `/sessions` endpoint will return a Session ID to your application. That Session ID must be passed to your client-side JavaScript so that it can initialize the Versapay Checkout Client SDK.\n\n# Versapay Checkout Client SDK <a name=\"client\"></a>\n\nThe Versapay Checkout JavaScript SDK can be used to initialize a hosted iFrame within your ecommerce website that contains all the fields needed to complete a secure credit card transaction while keeping your website out of scope for PCI compliance.\n\n## Setup\n\n### Install the Versapay library\n\nTo start using the SDK, load the library from the hosting url. This will give you access to functions in the versapay module.\n\n <!-- Load the client component -->\n <script src=\"https://ecommerce-api.versapay.com/client.js\"></script>\n\n <!-- Call functions in the versapay module -->\n <script>\n versapay.initClient(sessionId)\n </script>\n\n### Get a Session ID\n\nThe Versapay SDK requires a Session ID generated by a [server side API request](#serversetup). Once you have a Session ID, you can initialize the client.\n\n### Create a client instance\n\nCreate an instance of the client class using the versapay.initClient function, passing the session key generated on the server side as a parameter.\n\n <script>\n var client = versapay.initClient(sessionId)\n </script>\n\n### Add styles or fonts\n\nAlthough you can use the default styles and fonts of the checkout iFrame, it can also be configured with styles and fonts that fit with your ecommerce website. These can be passed as optional parameters to the initClient function.\n\nThe styles parameter should be sent as a json object of CSS selectors and properties. See the CSS Styling section for a list of supported properties and DOM element IDs that can be used in selectors.\n\nThe fontUrls parameter should be an array of urls that point to an embeddable Google Fonts link.\n\n <script>\n var styles = {\n html: {\n \"font-family\": \"DotGothic16\",\n },\n input: {\n \"font-size\": \"14pt\",\n \"color\": \"#3A3A3A\",\n },\n select: {\n \"font-size\": \"14pt\",\n \"color\": \"#3A3A3A\",\n }\n };\n\n var fontUrls = ['https://fonts.googleapis.com/css2?family=DotGothic16&display=swap']\n\n var client = versapay.initClient(clientSession, styles, fontUrls)\n </script>\n\n### Create DOM elements\n\nThe hosted iFrame requires two DOM elements, a form and an empty DOM element within the form to act as a container for the iframe. You will likely also want to include a way to submit the form, like a Submit or Pay button, and a way to display submission errors.\n\n <form id='form'>\n <div id='container'></div>\n <div>\n <button id='submit'>Pay</button>\n <span id='submitError'></span>\n </div>\n </form>\n <script>\n const form = document.querySelector('#form')\n const submit = document.querySelector('#submit')\n const submitError = document.querySelector('#submitError')\n </script>\n\n### Initialize the iframe and create a frame promise\n\nInitialize the iframe using the client.initFrame async function, passing the empty DOM element and the desired iFrame width and height as parameters. The return value of this function is a promise object that is resolved when the iframe and fields are ready.\n\n <script>\n const form = document.querySelector('#form')\n const submit = document.querySelector('#submit')\n\n versapay.initClient(clientSession).then(function(client) {\n frameReadyPromise = client.initFrame(document.querySelector('#container'), '500px', '250px')\n }\n </script>\n\n### Create the submit event handler\n\nAdd an event handler for the form submit event that calls the client.submit function. Note that the form.then() function is also useful for handling any other code that should be executed once the frame and fields are ready for input, like setting a form submit button to enabled.\n\n <script>\n const form = document.querySelector('#form')\n const submit = document.querySelector('#submit')\n\n versapay.initClient(clientSession).then(function(client) {\n frameReadyPromise = client.initFrame(document.querySelector('#container'), '500px', '250px')\n\n frameReadyPromise.then(function() {\n submit.removeAttribute('disabled')\n\n form.addEventListener('submit', function(event) {\n event.preventDefault()\n var tokenPromise = client.submit()\n\n tokenPromise.then(function(token) {\n console.log(token)\n })\n .catch(error => {\n console.log(error)\n submitError.textContent = error\n })\n })\n })\n }\n </script>\n\n### Receive the token from the iframe\n\nAfter the form is submitted a token will be generated by the iframe and passed back to the client page. The token will come back as the result of a promise resolution that is returned by the client.submit() method. After the token is received, it can be passed back up to the server side code to perform a charge, authorization, etc. If tokenization fails, the error can be used in the promise rejection .catch() method.\n\n form.addEventListener('submit', function(event) {\n event.preventDefault()\n \n // the promise is returned by the submit method\n var tokenPromise = client.submit()\n\n // the token value is the resolution of the promise\n tokenPromise.then(function(token) {\n // this console log shows the token value\n // replace this with code to pass the token back up to server-side code\n console.log(token)\n })\n .catch(error => {\n console.log(error)\n submitError.textContent = error\n })\n })\n\n## Example HTML Code\n\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Versapay JS Ecomm Library Demo</title>\n </head>\n <body>\n <form id='form'>\n <div id='container'></div>\n <div>\n <button id='submit'>Pay</button>\n <span id='submitError'></span>\n </div>\n </form>\n <script src=\"https://ecommerce-api.versapay.com/client.js\"></script>\n <script>\n const form = document.querySelector('#form')\n const submit = document.querySelector('#submit')\n const submitError = document.querySelector('#submitError')\n\n // Get the Session ID from the server side API.\n var clientSession = '1850bf0f-b12a-44d8-8edb-c289476a45df'\n \n // Set any custom styles to pass to the iFrame.\n var styles = {\n // html: {\n // \"font-family\": \"DotGothic16\",\n // },\n // input: {\n // \"font-size\": \"14pt\",\n // \"color\": \"#3A3A3A\",\n // },\n // select: {\n // \"font-size\": \"14pt\",\n // \"color\": \"#3A3A3A\",\n // }\n };\n\n // Set custom google font families to display in the iFrame.\n var fontUrls = ['https://fonts.googleapis.com/css2?family=DotGothic16&display=swap']\n \n // Initialize the client with the Session ID and any custom styles or fonts.\n var client = versapay.initClient(clientSession, styles, fontUrls)\n \n // Instantiate the iFrame from client object using the target dom and set the frame height and width.\n var frameReadyPromise = client.initFrame(document.querySelector('#container'), '300px', '500px')\n\n // The client.initFrame function returns a promise that resolves when the iFrame is ready to be used\n frameReadyPromise.then(function() {\n // Code that is placed here will run after the iFrame is ready.\n // For instance, you can disable your form submit button and \n // only allow clicks after the iFrame is ready.\n submit.removeAttribute('disabled')\n\n // Add an event listener for your form submission.\n form.addEventListener('submit', function(event) {\n event.preventDefault()\n\n // Use the client.submit function to tell the iFrame to tokenize the entered card information.\n var tokenPromise = client.submit()\n\n // The client.submit function returns a promise that resolves when the API call to tokenize the card completes.\n tokenPromise.then(function(token) {\n // When the tokenization is successful, the promise's .then() method will execute.\n submitError.textContent = ''\n // The promise will resolve with a token string for the card, which can then be passed back to\n // your server side code for additional payment transactions.\n console.log(token)\n })\n .catch(error => {\n // When the tokenization fails, the promise's .catch() method will execute.\n console.log(error)\n // The promise will reject with an error message, which can then be shown to the user.\n submitError.textContent = error\n })\n })\n })\n </script>\n </body>\n </html>\n\n## CSS Styling\n\n---\n\n### DOM Element IDs\n\nThe following IDs can be used as CSS selectors in the style json that can be passed as a parameter to initClient.\n\n #accountNoDiv\n #accountNo\n #cardholderNameDiv\n #cardholderName\n #expDateDiv\n #expDate\n #expMonth\n #expYear\n #cvvDiv\n #cvv\n\n### Supported CSS properties\n\n '-moz-appearance',\n '-moz-osx-font-smoothing',\n '-moz-tap-highlight-color',\n '-moz-transition',\n '-webkit-appearance',\n '-webkit-font-smoothing',\n '-webkit-tap-highlight-color',\n '-webkit-transition',\n 'appearance',\n 'background-color',\n 'border',\n 'border-radius',\n 'color',\n 'direction',\n 'font',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-variant-alternates',\n 'font-variant-caps',\n 'font-variant-east-asian',\n 'font-variant-ligatures',\n 'font-variant-numeric',\n 'font-weight',\n 'letter-spacing',\n 'line-height',\n 'margin',\n 'margin-top',\n 'margin-right',\n 'margin-bottom',\n 'margin-left',\n 'opacity',\n 'outline',\n 'padding',\n 'padding-top',\n 'padding-right',\n 'padding-bottom',\n 'padding-left',\n 'text-align',\n 'text-shadow',\n 'transition',\n 'flex-direction',\n 'flex-flow',\n 'flex-basis',\n 'flex-shrink',\n 'flex-grow',\n 'flex-wrap',\n 'justify-content',\n 'flex',\n 'align-self',\n 'align-items',\n 'align-content' \n# Server-side Orders and Payments <a name=\"serverpayments\"></a>\n\nOnce your client-side script has received the payment token from the Versapay Client SDK and passed it to your server-side application, you need to use the API to create and order and process a payment. Depending on your checkout scenario, this can be done in a single step, or it can be split into multiple steps to support more complex flows. \n\nWhen an order is created, it has a status of either Finalized or Not Finalized. Only Finalized orders will be brought into your ERP or order fulfillment system. If you are attempting to use a single payment method for the order, you can use the one-step process. The one-step process will automatically Finalize the order if the payment is approved. Other scenarios, which may include zero payments (e.g., the order is being paid via a Purchase Order) or multiple payments (e.g., the order payment is being split between two credit cards), require that you:\n1. Create the order without any payments\n2. Request zero or more payments necessary for order completion\n3. If all payments are successful, Finalize the order to signal that it is ready to be retrieved by the ERP or order fulfillment system\n\n## Create an Order\n\nWhen you POST to `/sessions/{sessionId}/sales`, the Versapay system will create an order based on the data that you supply in your request. Your POST can include a `payment` element if the intent is to take exactly one payment for the order.\n\nIf successful, the API will return an Order ID, the Finalization status, and, if a payment was requested, the payment response information.\n\nAlways check the Finalization status of the order. If the payment was approved, but the order was not automatically finalized, you should send a PATCH request to finalize the order yourself.\n\n## Create a Payment\n\nIf your intent is to process multiple payments against an order, and you have already create the order and have an Order ID, you can POST to the `/sessions/{sessionId}/sales/{saleId}/payments` endpoint to request a payment against the order.\n\nOnce all payments are successful, you must finalize the order.\n\n## Order Finalization\n\nWhen you are finished with an order and are ready for the ERP or order fulfillment system to retrieve it, you can finalize the order by sending a PATCH request to the `/sessions/{sessionId}/sales/{saleId}` endpoint. If finalization is successful, the API will return a response indicating that the order has been finalized.\n",
6 "contact": {
7 "name": "Versapay",
8 "url": "https://www.versapay.com"
9 },
10 "version": "1.1.0-External"
11 },
12 "servers": [
13 {
14 "url": "https://{subdomain}.versapay.com/api/v1",
15 "variables": {
16 "subdomain": {
17 "default": "ecommerce-api"
18 }
19 }
20 }
21 ],
22 "tags": [
23 {
24 "name": "developers",
25 "description": "Operations available to developers"
26 }
27 ],
28 "paths": {
29 "/sessions": {
30 "post": {
31 "tags": [
32 "developers"
33 ],
34 "summary": "create a session",
35 "description": "By passing in the appropriate options, you can create an iframe \nsession with options that meet your needs. If successful, this operation will return a session id in the \"id\" property of the response. Your application can then use that session id when initializing our client-side JavaScript library, which will inject an iframe into your page. The iframe will be rendered using the options you specify. When sensitive payment data is entered into the iframe, it will be tokenized by our servers, and that token will be returned to your page via JavaScript. Your page should post that token back to your server and use it to make a follow-on API call to create an order and payment. \n",
36 "operationId": "createSession",
37 "requestBody": {
38 "description": "These are the options for the iframe session",
39 "content": {
40 "application/json": {
41 "schema": {
42 "$ref": "#/components/schemas/SessionRequest"
43 }
44 }
45 },
46 "required": true
47 },
48 "responses": {
49 "201": {
50 "description": "The session has been created",
51 "content": {
52 "application/json": {
53 "schema": {
54 "$ref": "#/components/schemas/SessionResponse"
55 }
56 }
57 }
58 },
59 "401": {
60 "description": "Gateway authentication error",
61 "content": {
62 "application/json": {
63 "schema": {
64 "$ref": "#/components/schemas/Error"
65 }
66 }
67 }
68 }
69 }
70 }
71 },
72 "/wallets": {
73 "post": {
74 "tags": [
75 "developers"
76 ],
77 "summary": "create a wallet for a known user",
78 "description": "This operation will create a new wallet for a known customer. If the customer is using a guest checkout feature, wallets should not be used until an account is created and the customer becomes known.",
79 "requestBody": {
80 "description": "These are the authentication parameters for the gateway",
81 "content": {
82 "application/json": {
83 "schema": {
84 "$ref": "#/components/schemas/SimpleRequest"
85 }
86 }
87 },
88 "required": true
89 },
90 "responses": {
91 "201": {
92 "description": "The wallet has been created",
93 "content": {
94 "application/json": {
95 "schema": {
96 "$ref": "#/components/schemas/WalletResponse"
97 }
98 }
99 }
100 },
101 "400": {
102 "description": "Bad input parameter",
103 "content": {
104 "application/json": {
105 "schema": {
106 "$ref": "#/components/schemas/Error"
107 }
108 }
109 }
110 }
111 }
112 }
113 },
114 "/sessions/{id}/sales": {
115 "post": {
116 "tags": [
117 "developers"
118 ],
119 "summary": "process a sale",
120 "description": "This operation will send a new order to our server. You can optionally process a payment transaction in a single operation. However, if you need to process multiple payment transactions, you should use the seperate payment operation. If a payment is included, the order will be finalized if the payment is approved. If a payment is not included, the order will not be finalized, and a PATCH request will be required to finalize the order once all payments have been processed.",
121 "parameters": [
122 {
123 "name": "id",
124 "in": "path",
125 "description": "Session ID",
126 "required": true,
127 "style": "simple",
128 "explode": false,
129 "schema": {
130 "$ref": "#/components/schemas/SessionID"
131 }
132 }
133 ],
134 "requestBody": {
135 "content": {
136 "application/json": {
137 "schema": {
138 "$ref": "#/components/schemas/Sale"
139 }
140 }
141 }
142 },
143 "responses": {
144 "201": {
145 "description": "The order has been created",
146 "content": {
147 "application/json": {
148 "schema": {
149 "$ref": "#/components/schemas/SaleResponse"
150 }
151 }
152 }
153 },
154 "400": {
155 "description": "Bad input parameter",
156 "content": {
157 "application/json": {
158 "schema": {
159 "$ref": "#/components/schemas/Error"
160 }
161 }
162 }
163 },
164 "404": {
165 "description": "Session not found",
166 "content": {
167 "application/json": {
168 "schema": {
169 "$ref": "#/components/schemas/Error"
170 }
171 }
172 }
173 }
174 }
175 }
176 },
177 "/sessions/{id}/sales/{saleid}": {
178 "patch": {
179 "tags": [
180 "developers"
181 ],
182 "summary": "update a sale",
183 "description": "This operation will update an existing order on our server to finalize the order and get it ready for import.",
184 "parameters": [
185 {
186 "name": "id",
187 "in": "path",
188 "description": "Session ID",
189 "required": true,
190 "style": "simple",
191 "explode": false,
192 "schema": {
193 "$ref": "#/components/schemas/SessionID"
194 }
195 },
196 {
197 "name": "saleid",
198 "in": "path",
199 "description": "Order ID",
200 "required": true,
201 "style": "simple",
202 "explode": false,
203 "schema": {
204 "$ref": "#/components/schemas/OrderID"
205 }
206 }
207 ],
208 "responses": {
209 "202": {
210 "description": "The order has been updated",
211 "content": {
212 "application/json": {
213 "schema": {
214 "$ref": "#/components/schemas/SaleResponse"
215 }
216 }
217 }
218 },
219 "400": {
220 "description": "Bad input parameter",
221 "content": {
222 "application/json": {
223 "schema": {
224 "$ref": "#/components/schemas/Error"
225 }
226 }
227 }
228 },
229 "404": {
230 "description": "Session not found",
231 "content": {
232 "application/json": {
233 "schema": {
234 "$ref": "#/components/schemas/Error"
235 }
236 }
237 }
238 }
239 }
240 }
241 },
242 "/sessions/{id}/sales/{saleid}/payments": {
243 "post": {
244 "tags": [
245 "developers"
246 ],
247 "summary": "process a payment",
248 "description": "Use this operation to authorize a payment instrument for an existing sale. You must have already created the sale.",
249 "parameters": [
250 {
251 "name": "id",
252 "in": "path",
253 "description": "Session ID",
254 "required": true,
255 "style": "simple",
256 "explode": false,
257 "schema": {
258 "$ref": "#/components/schemas/SessionID"
259 }
260 },
261 {
262 "name": "saleid",
263 "in": "path",
264 "description": "Order ID",
265 "required": true,
266 "style": "simple",
267 "explode": false,
268 "schema": {
269 "$ref": "#/components/schemas/OrderID"
270 }
271 }
272 ],
273 "requestBody": {
274 "content": {
275 "application/json": {
276 "schema": {
277 "$ref": "#/components/schemas/Payment"
278 }
279 }
280 }
281 },
282 "responses": {
283 "201": {
284 "description": "The payment has been created",
285 "content": {
286 "application/json": {
287 "schema": {
288 "$ref": "#/components/schemas/PaymentResponse"
289 }
290 }
291 }
292 },
293 "400": {
294 "description": "Bad input parameter",
295 "content": {
296 "application/json": {
297 "schema": {
298 "$ref": "#/components/schemas/Error"
299 }
300 }
301 }
302 },
303 "404": {
304 "description": "Session not found",
305 "content": {
306 "application/json": {
307 "schema": {
308 "$ref": "#/components/schemas/Error"
309 }
310 }
311 }
312 }
313 }
314 }
315 }
316 },
317 "components": {
318 "schemas": {
319 "Error": {
320 "type": "object",
321 "properties": {
322 "message": {
323 "type": "string",
324 "description": "The error message",
325 "example": "not found"
326 },
327 "errors": {
328 "type": "array",
329 "description": "A collection of errors",
330 "items": {
331 "$ref": "#/components/schemas/Error_errors"
332 }
333 }
334 },
335 "description": "Error"
336 },
337 "SessionID": {
338 "type": "string",
339 "description": "The session ID returned by a POST to /sessions",
340 "format": "uuid",
341 "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
342 },
343 "WalletID": {
344 "minLength": 1,
345 "pattern": "^[0-9A-Z]+",
346 "type": "string",
347 "description": "The wallet ID returned by a POST to /wallets",
348 "example": "1NQGAW7N4S7H"
349 },
350 "OrderID": {
351 "minLength": 1,
352 "type": "string",
353 "description": "The order ID returned by a POST to /sessions/{id}/sales",
354 "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
355 },
356 "FundToken": {
357 "minLength": 1,
358 "pattern": "^[0-9A-Za-z-]+",
359 "type": "string",
360 "description": "The token associated with a funding source",
361 "example": "1NQGAW7N4S7H"
362 },
363 "PaymentMethod": {
364 "type": "string",
365 "description": "The payment type",
366 "example": "creditCard",
367 "enum": [
368 "creditCard",
369 "ach"
370 ]
371 },
372 "AccountHolder": {
373 "minLength": 1,
374 "type": "string",
375 "description": "The name of the cardholder",
376 "example": "Jane Smith"
377 },
378 "CardExpirationMonth": {
379 "maximum": 12,
380 "minimum": 1,
381 "type": "integer",
382 "description": "The expiration month, expressed as an integer from 1 (January) to 12 (December)",
383 "example": 12
384 },
385 "CardExpirationYear": {
386 "maximum": 2099,
387 "minimum": 2020,
388 "type": "integer",
389 "description": "The expiration year, expressed as a 4-digit year",
390 "example": 2030
391 },
392 "CardBrand": {
393 "type": "string",
394 "description": "The card brand",
395 "example": "visa",
396 "enum": [
397 "visa",
398 "master",
399 "american_express",
400 "discover"
401 ]
402 },
403 "BankRoutingNumber": {
404 "maxLength": 9,
405 "minLength": 8,
406 "pattern": "^\\d{8,9}$",
407 "type": "string",
408 "description": "The routing number of the financial institution",
409 "example": "123456780"
410 },
411 "AccountNumberLastFour": {
412 "pattern": "^\\d{4,4}",
413 "type": "string",
414 "description": "The last four digits of the account number",
415 "example": "1234"
416 },
417 "Currency": {
418 "maxLength": 3,
419 "minLength": 3,
420 "pattern": "^[A-Z]{3,3}$",
421 "type": "string",
422 "description": "The uppercase 3-letter ISO currency code",
423 "example": "USD"
424 },
425 "Sale": {
426 "required": [
427 "billingAddress",
428 "currency",
429 "lines",
430 "orderNumber",
431 "shippingAddress"
432 ],
433 "type": "object",
434 "properties": {
435 "customerNumber": {
436 "type": "string",
437 "description": "The Customer identifier as the Customer is known to the ERP system",
438 "example": "C1234"
439 },
440 "orderNumber": {
441 "minLength": 1,
442 "type": "string",
443 "description": "The Order identifier generated by the shopping cart system",
444 "example": "SO1234"
445 },
446 "purchaseOrderNumber": {
447 "type": "string",
448 "description": "The customer's Purchase Order Number",
449 "example": "PO1234"
450 },
451 "shippingAgentNumber": {
452 "type": "string",
453 "description": "The Shipping Agent identifier known to the ERP system",
454 "example": "USPS"
455 },
456 "shippingAgentServiceNumber": {
457 "type": "string",
458 "description": "The Shipping Agent Service identifier known to the ERP system",
459 "example": "PRIORITY"
460 },
461 "shippingAgentDescription": {
462 "type": "string",
463 "description": "A description or name of the Shipping Agent",
464 "example": "United States Postal Service"
465 },
466 "shippingAgentServiceDescription": {
467 "type": "string",
468 "description": "A description or name of the Shipping Agent Service",
469 "example": "Priority Mail"
470 },
471 "currency": {
472 "$ref": "#/components/schemas/Currency"
473 },
474 "billingAddress": {
475 "$ref": "#/components/schemas/Address"
476 },
477 "shippingAddress": {
478 "$ref": "#/components/schemas/Address"
479 },
480 "lines": {
481 "minItems": 1,
482 "type": "array",
483 "description": "The collection of order lines",
484 "items": {
485 "$ref": "#/components/schemas/SaleLine"
486 }
487 },
488 "shippingAmount": {
489 "minimum": 0,
490 "type": "number",
491 "description": "The amount being charged for freight, expressed in the currency of the current sale",
492 "format": "float",
493 "example": 5.05
494 },
495 "discountAmount": {
496 "minimum": 0,
497 "type": "number",
498 "description": "The order-level discount amount, expressed as a positive value, in the currency of the current sale",
499 "format": "float",
500 "example": 10.5
501 },
502 "taxAmount": {
503 "minimum": 0,
504 "type": "number",
505 "description": "The sales tax amount, expressed in the currency of the current sale",
506 "format": "float",
507 "example": 1.05
508 },
509 "payment": {
510 "$ref": "#/components/schemas/Payment"
511 }
512 },
513 "description": "Order details"
514 },
515 "SaleLine": {
516 "required": [
517 "description",
518 "number",
519 "price",
520 "quantity"
521 ],
522 "type": "object",
523 "properties": {
524 "type": {
525 "type": "string",
526 "description": "The type of sales line (e.g., Item, Resource, G/L Account), which is a valid sales line type for the ERP system",
527 "example": "Item",
528 "default": "Item"
529 },
530 "number": {
531 "minLength": 1,
532 "type": "string",
533 "description": "The identifier for the current sales line, as known by the ERP system (e.g., if the type is Item, this would be the item identifier)",
534 "example": "I1234"
535 },
536 "description": {
537 "type": "string",
538 "description": "A description for the sales line",
539 "example": "Widget"
540 },
541 "price": {
542 "type": "number",
543 "description": "The unit price, expressed in the currency of the current sale",
544 "format": "float",
545 "example": 1.23
546 },
547 "quantity": {
548 "type": "number",
549 "description": "The quantity sold",
550 "format": "float",
551 "example": 1.5
552 },
553 "discount": {
554 "minimum": 0,
555 "type": "number",
556 "description": "The line discount amount, expressed as a positive value, in the currency of the current sale",
557 "format": "float",
558 "example": 0
559 }
560 },
561 "description": "A line item for an order"
562 },
563 "Address": {
564 "required": [
565 "address1",
566 "city",
567 "contactFirstName",
568 "contactLastName",
569 "country",
570 "email",
571 "stateOrProvince"
572 ],
573 "type": "object",
574 "properties": {
575 "contactFirstName": {
576 "type": "string",
577 "description": "The contact's first name",
578 "example": "Alice"
579 },
580 "contactLastName": {
581 "type": "string",
582 "description": "The contact's last name",
583 "example": "Smith"
584 },
585 "companyName": {
586 "type": "string",
587 "description": "The company name",
588 "example": "My Company"
589 },
590 "address1": {
591 "minLength": 1,
592 "type": "string",
593 "description": "The first address line",
594 "example": "123 Main Street"
595 },
596 "address2": {
597 "type": "string",
598 "description": "The second address line",
599 "example": "Apartment 1"
600 },
601 "city": {
602 "minLength": 1,
603 "type": "string",
604 "description": "The city",
605 "example": "Anytown"
606 },
607 "stateOrProvince": {
608 "type": "string",
609 "description": "The state or province code",
610 "example": "CA"
611 },
612 "postCode": {
613 "type": "string",
614 "description": "The ZIP or post code",
615 "example": "55555"
616 },
617 "country": {
618 "maxLength": 2,
619 "minLength": 2,
620 "pattern": "^[A-Z]{2}$",
621 "type": "string",
622 "description": "The uppercase 2-character ISO country code",
623 "example": "US"
624 },
625 "phone": {
626 "type": "string",
627 "description": "The phone number",
628 "example": "555-555-5555"
629 },
630 "email": {
631 "type": "string",
632 "description": "The email address for the contact",
633 "format": "email",
634 "example": "me@example.com"
635 }
636 },
637 "description": "An Address"
638 },
639 "Payment": {
640 "required": [
641 "amount",
642 "capture",
643 "token",
644 "type"
645 ],
646 "type": "object",
647 "properties": {
648 "type": {
649 "$ref": "#/components/schemas/PaymentMethod"
650 },
651 "token": {
652 "$ref": "#/components/schemas/FundToken"
653 },
654 "amount": {
655 "minimum": 0,
656 "type": "number",
657 "description": "The payment amount, expressed in the currency of the current sale",
658 "format": "float",
659 "example": 123.45
660 },
661 "capture": {
662 "type": "boolean",
663 "description": "Indicates if the gateway should capture the funds or just reserve the funds via an authorization",
664 "example": false
665 }
666 },
667 "description": "A Payment"
668 },
669 "GatewayAuthorization": {
670 "oneOf": [
671 {
672 "$ref": "#/components/schemas/UnifiedAuthorization"
673 },
674 {
675 "$ref": "#/components/schemas/TPro4Authorization"
676 }
677 ]
678 },
679 "UnifiedAuthorization": {
680 "required": [
681 "apiKey",
682 "apiToken"
683 ],
684 "type": "object",
685 "properties": {
686 "apiToken": {
687 "minLength": 1,
688 "type": "string",
689 "description": "The API Token for the gateway",
690 "example": "1a2B345ZYx0987yYuiTr"
691 },
692 "apiKey": {
693 "minLength": 1,
694 "type": "string",
695 "description": "The API Key for the gateway",
696 "example": "1a2B345ZYx0987yYuiTr"
697 }
698 },
699 "description": "Versapay authentication credentials"
700 },
701 "TPro4Authorization": {
702 "required": [
703 "accounts",
704 "email",
705 "gateway",
706 "password"
707 ],
708 "type": "object",
709 "properties": {
710 "gateway": {
711 "type": "string",
712 "description": "The name of the gateway",
713 "example": "my-gateway"
714 },
715 "email": {
716 "type": "string",
717 "description": "The email associated with the gateway account",
718 "format": "email",
719 "example": "me@example.com"
720 },
721 "password": {
722 "type": "string",
723 "description": "The password associated with the gateway account",
724 "format": "password",
725 "example": "P@ssword1"
726 },
727 "accounts": {
728 "minItems": 1,
729 "type": "array",
730 "description": "The collection of gateway accounts",
731 "items": {
732 "$ref": "#/components/schemas/TPro4Account"
733 }
734 }
735 },
736 "description": "Credentials for the TPro4 gateway"
737 },
738 "TPro4Account": {
739 "required": [
740 "account",
741 "type"
742 ],
743 "type": "object",
744 "properties": {
745 "type": {
746 "$ref": "#/components/schemas/PaymentMethod"
747 },
748 "account": {
749 "type": "string",
750 "description": "The name of the gateway account",
751 "example": "cc"
752 }
753 },
754 "description": "A TPro4 gateway account"
755 },
756 "SessionRequest": {
757 "required": [
758 "gatewayAuthorization",
759 "options"
760 ],
761 "type": "object",
762 "properties": {
763 "gatewayAuthorization": {
764 "$ref": "#/components/schemas/GatewayAuthorization"
765 },
766 "options": {
767 "$ref": "#/components/schemas/SessionOption"
768 }
769 },
770 "description": "A new session request"
771 },
772 "SimpleRequest": {
773 "required": [
774 "gatewayAuthorization"
775 ],
776 "type": "object",
777 "properties": {
778 "gatewayAuthorization": {
779 "$ref": "#/components/schemas/GatewayAuthorization"
780 }
781 },
782 "description": "A simple request"
783 },
784 "SessionResponse": {
785 "required": [
786 "id"
787 ],
788 "type": "object",
789 "properties": {
790 "id": {
791 "$ref": "#/components/schemas/SessionID"
792 }
793 }
794 },
795 "SaleResponse": {
796 "required": [
797 "finalized",
798 "orderId"
799 ],
800 "type": "object",
801 "properties": {
802 "orderId": {
803 "$ref": "#/components/schemas/OrderID"
804 },
805 "finalized": {
806 "type": "boolean",
807 "description": "The finalization status of the order (only finalized orders will be imported into the ERP)",
808 "example": true
809 },
810 "payment": {
811 "$ref": "#/components/schemas/PaymentResponse"
812 }
813 },
814 "description": "A response containing order identification information"
815 },
816 "WalletResponse": {
817 "required": [
818 "walletId"
819 ],
820 "type": "object",
821 "properties": {
822 "walletId": {
823 "$ref": "#/components/schemas/WalletID"
824 }
825 },
826 "description": "A response containing wallet information"
827 },
828 "PaymentResponse": {
829 "required": [
830 "accountNumberLastFour",
831 "accountType",
832 "token"
833 ],
834 "type": "object",
835 "properties": {
836 "approvalCode": {
837 "type": "string",
838 "description": "The payment transaction approval code",
839 "example": "123456"
840 },
841 "avsResponseCode": {
842 "type": "string",
843 "description": "The code representing the address validation status of the transaction",
844 "example": "M"
845 },
846 "accountNumberLastFour": {
847 "type": "string",
848 "description": "The last four digits of the account number",
849 "example": "1234"
850 },
851 "accountType": {
852 "type": "string",
853 "description": "The type or brand of account being used for payment",
854 "example": "Visa"
855 },
856 "token": {
857 "$ref": "#/components/schemas/FundToken"
858 },
859 "amount": {
860 "type": "number",
861 "description": "The amount approved by the payment processor, which may be less than the amount requested",
862 "format": "float",
863 "example": 10
864 },
865 "transactionId": {
866 "type": "string",
867 "description": "The transaction ID"
868 }
869 },
870 "description": "A response containing payment details"
871 },
872 "SessionOption": {
873 "type": "object",
874 "properties": {
875 "fields": {
876 "$ref": "#/components/schemas/FieldOptions"
877 },
878 "wallet": {
879 "$ref": "#/components/schemas/WalletOptions"
880 },
881 "paymentTypes": {
882 "$ref": "#/components/schemas/PaymentTypes"
883 }
884 },
885 "additionalProperties": {
886 "oneOf": [
887 {
888 "type": "object"
889 },
890 {
891 "type": "boolean"
892 },
893 {
894 "type": "integer"
895 },
896 {
897 "type": "string"
898 },
899 {
900 "type": "number"
901 }
902 ]
903 },
904 "description": "An option for a specific session"
905 },
906 "WalletOptions": {
907 "properties": {
908 "id": {
909 "$ref": "#/components/schemas/WalletID"
910 },
911 "allowAdd": {
912 "type": "boolean",
913 "description": "Set this option to true if the customer should be allowed to add new payment methods to the wallet",
914 "example": true
915 },
916 "allowEdit": {
917 "type": "boolean",
918 "description": "Set this option to true if the customer should be allowed to edit existing wallet items",
919 "example": true
920 },
921 "allowDelete": {
922 "type": "boolean",
923 "description": "Set this option to true if the customer should be allowed to remove items from the wallet",
924 "example": true
925 },
926 "creditCardTokens": {
927 "$ref": "#/components/schemas/CreditCardTokens"
928 },
929 "bankAccountTokens": {
930 "$ref": "#/components/schemas/BankAccountTokens"
931 }
932 },
933 "description": "Options for wallet behavior"
934 },
935 "PaymentTypes": {
936 "type": "array",
937 "items": {
938 "$ref": "#/components/schemas/PaymentType"
939 }
940 },
941 "PaymentType": {
942 "required": [
943 "label",
944 "name"
945 ],
946 "type": "object",
947 "properties": {
948 "name": {
949 "$ref": "#/components/schemas/PaymentMethod"
950 },
951 "label": {
952 "type": "string",
953 "description": "The payment method display name",
954 "example": "Credit Card"
955 },
956 "promoted": {
957 "type": "boolean",
958 "description": "Set this option to true to display this payment method in a promoted fashion",
959 "example": false
960 },
961 "fields": {
962 "$ref": "#/components/schemas/FieldOptions"
963 }
964 },
965 "additionalProperties": {
966 "description": "Reserved for future use",
967 "oneOf": [
968 {
969 "type": "object"
970 },
971 {
972 "type": "boolean"
973 },
974 {
975 "type": "integer"
976 },
977 {
978 "type": "string"
979 },
980 {
981 "type": "number"
982 }
983 ]
984 },
985 "description": "A payment type or method"
986 },
987 "CreditCardTokens": {
988 "type": "array",
989 "description": "A collection of credit card tokens",
990 "items": {
991 "$ref": "#/components/schemas/CreditCardToken"
992 }
993 },
994 "CreditCardToken": {
995 "required": [
996 "token"
997 ],
998 "properties": {
999 "token": {
1000 "$ref": "#/components/schemas/FundToken"
1001 },
1002 "accountHolder": {
1003 "$ref": "#/components/schemas/AccountHolder"
1004 },
1005 "accountNumberLastFour": {
1006 "$ref": "#/components/schemas/AccountNumberLastFour"
1007 },
1008 "expirationMonth": {
1009 "$ref": "#/components/schemas/CardExpirationMonth"
1010 },
1011 "expirationYear": {
1012 "$ref": "#/components/schemas/CardExpirationYear"
1013 },
1014 "brand": {
1015 "$ref": "#/components/schemas/CardBrand"
1016 },
1017 "editable": {
1018 "type": "boolean",
1019 "description": "Set to true if the payment method should be editable by the customer",
1020 "example": true
1021 }
1022 },
1023 "description": "Token information for a credit card"
1024 },
1025 "BankAccountTokens": {
1026 "type": "array",
1027 "items": {
1028 "$ref": "#/components/schemas/BankAccountToken"
1029 }
1030 },
1031 "BankAccountToken": {
1032 "required": [
1033 "token"
1034 ],
1035 "properties": {
1036 "token": {
1037 "$ref": "#/components/schemas/FundToken"
1038 },
1039 "accountHolder": {
1040 "$ref": "#/components/schemas/AccountHolder"
1041 },
1042 "routingNumber": {
1043 "$ref": "#/components/schemas/BankRoutingNumber"
1044 },
1045 "accountNumberLastFour": {
1046 "$ref": "#/components/schemas/AccountNumberLastFour"
1047 },
1048 "currency": {
1049 "$ref": "#/components/schemas/Currency"
1050 },
1051 "editable": {
1052 "type": "boolean",
1053 "description": "Set to true if the payment method should be editable by the customer",
1054 "example": true
1055 }
1056 },
1057 "description": "Token information for a bank acocunt"
1058 },
1059 "FieldOptions": {
1060 "type": "array",
1061 "description": "A collection of field options",
1062 "items": {
1063 "$ref": "#/components/schemas/FieldOption"
1064 }
1065 },
1066 "FieldOption": {
1067 "required": [
1068 "label",
1069 "name"
1070 ],
1071 "type": "object",
1072 "properties": {
1073 "name": {
1074 "type": "string",
1075 "description": "Field name",
1076 "example": "expDate"
1077 },
1078 "label": {
1079 "type": "string",
1080 "description": "Field display name",
1081 "example": "Expiration Date"
1082 },
1083 "placeholder": {
1084 "type": "string",
1085 "description": "The placeholder shown on the form",
1086 "example": "MM / YY"
1087 },
1088 "errorLabel": {
1089 "type": "string",
1090 "description": "The error message displayed for an invalid entry",
1091 "example": "Please check the Expiration Date"
1092 },
1093 "allowLabelUpdate": {
1094 "type": "boolean",
1095 "description": "Set to true if the client-side code should be allowed to override the label",
1096 "example": true
1097 },
1098 "id": {
1099 "minLength": 1,
1100 "type": "string",
1101 "description": "The DOM ID of the field",
1102 "example": "ddlExpDate"
1103 }
1104 },
1105 "additionalProperties": {
1106 "description": "Reserved for future use",
1107 "oneOf": [
1108 {
1109 "type": "boolean"
1110 },
1111 {
1112 "type": "integer"
1113 },
1114 {
1115 "type": "string"
1116 },
1117 {
1118 "type": "number"
1119 }
1120 ]
1121 },
1122 "description": "Options for a single field"
1123 },
1124 "Error_errors": {
1125 "type": "object",
1126 "properties": {
1127 "path": {
1128 "type": "string",
1129 "description": "The path that generated the error",
1130 "example": "/foo"
1131 },
1132 "message": {
1133 "type": "string",
1134 "description": "The error message",
1135 "example": "not found"
1136 }
1137 },
1138 "description": "An error"
1139 }
1140 }
1141 }
1142}