{"_id":"1click-api","_rev":"3-7a0ae81c6e0d5cfbe35fabfdace93073","name":"1click-api","time":{"modified":"2022-04-04T10:12:54.223Z","created":"2017-06-19T14:18:14.476Z","0.23.0":"2017-06-19T14:18:14.476Z","1.1.0":"2017-07-10T20:50:31.772Z"},"maintainers":[{"name":"nicolaschenet","email":"ironic51@gmail.com"}],"dist-tags":{"latest":"1.1.0"},"description":"API to handle 1click button","readme":"# 1click-api [![Build Status](https://travis-ci.com/OystParis/1click-api.svg?token=Q1A95RbZGQpb1jK1qJ8Z&branch=master)](https://travis-ci.com/OystParis/1click-api)\n\n---\n\n## Handlers\n\n#### _Merchant_\n\nNeeds an valid merchant ApiKey\nNeeds header `Authorization: Bearer <APIKEY>`\n\n#### _Oyst_\n\nNeeds header `Oyst-Authorization: Oyst <DATA>`\n\nWhere `<DATA>` is a `base64` encoded `stringified` object\n\n```json\n{\n    \"m\": \"<MERCHANT_ID>\",\n    \"t\": \"<MERCHANT_TOKEN>\" // Generated by `POST` /orders/authorize\n}\n```\n#### _Sessions_\n\nNeeds header `oyst-session`\n\nReturns a `403` if header is not present\n\n## Routes\n\n### Error handling\nWhen calling this API except for internal errors, the API should return a json\n\n```json\n{\n    \"success\": false,\n    \"error\": {\n        \"status\": \"<API-SHORT-CODE>-<ERROR-CODE>\",\n        \"status_text\": \"<ERROR-MSG-USING-i18n>\"\n    }\n}\n```\n\n### `POST` /orders/authorize\n\nHandle the server to server authentication for the oneclick. This route should be called by the merchant during the `function getOneclickUrl()`.\nThe iframe url is returned.\n\n###### Payload:\n```javascript\nJoi.object({\n  product_reference: Joi.string().required(),\n  variation_reference: Joi.string().optional(),\n  user: Joi.object().optional(),\n  quantity: Joi.number().integer().default(1)\n})\n```\n###### Handler: _merchant_\n\n###### Returns\n* `403` on authentication failure\n* On success\n\n```json\n{\n    \"success\": true,\n    \"url\": \"http://url_to_front_application\"\n}\n```\n\n### `GET` /version\n\nInformations are in `package.json`\n\n###### Returns\n\n```json\n{\n    \"name\": \"APPLICATION_NAME\",\n    \"version\": \"APPLICATION_VERSION\"\n}\n```\n\n### `POST` /orders\n\nHandle the order creation when user is known.\n\nIt calls:\n\n* payment-api\n* user-api\n* catalog-api\n\n###### Payload\n\n```javascript\nJoi.object({\n  encrypted_card: Joi.string().required()\n}).allow(null)\n```\n\n`encrypted_card` should be send only when user changes his card\n\n###### Handler: _Oyst_ _Session_\n\n###### Returns\n\n```json\n{\n    \"success\": true,\n    \"id\": \"ORDER_UUID\",\n    \"product\": {},\n    \"user\": {},\n    \"order\": {}\n}\n```\n\n### `DELETE` /orders/{:id}\n\nDelete specific order and clean associated session\n\nIt calls:\n\n* payment-api\n* user-api\n* catalog-api\n\n###### QueryParams\n\n```javascript\nJoi.object({\n  id: Joi.string().guid().required()\n})\n```\n\n###### Handler: _Oyst_ _Session_\n\n###### Returns\n\n```json\n{\n    \"success\": true\n}\n```\n\n### `GET` /users\n\nCheck if user exists using the phone number. If found, sms is send with a link\n\n###### QueryParams\n\n```javascript\nJoi.object({\n  phone: phoneRule.phone().mobile().required()\n})\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n\n###### Handler: _Oyst_\n\n\n###### Returns\n\n```json\n{\n    \"success\": true, // When user is found or false otherwhise\n    \"sms\": true, // Or false if sms was not send\n    \"channel\": \"PUSHER_CHANNEL_TO_LISTEN_TO\",\n    \"event\": \"PUSHER_EVENT_TO_LISTEN_TO\",\n    \"phone\": \"+33601020304\",\n    \"can_retry\": true // false if limit is reached\n}\n```\n\n### `POST` /users/card\n\nCalled when user is not found. Store the `encrypted_card` in REDIS Session.\nThen send a SMS with a link that display a code. Like 3DS\n\n###### Payload\n\n```javascript\nJoi.object({\n  encrypted_card: Joi.string().required()\n})\n```\n\n###### Handler: _Oyst_\n\n\n###### Returns\n\n```json\n{\n    \"success\": true, // Or false if sms was not send\n    \"channel\": \"PUSHER_CHANNEL_TO_LISTEN_TO\",\n    \"event\": \"PUSHER_EVENT_TO_LISTEN_TO\",\n    \"phone\": \"+33601020304\",\n    \"can_retry\": true, // false if limit is reached\n    \"code\": true\n}\n```\n\n### `GET` /users/phone/mfa\n\nActivate the code when user clicked on the SMS link\n\n###### QueryParams\n\n```javascript\nJoi.object({\n    id: Joi.string().guid().required(),\n    p: phoneRule.phone().mobile().required()\n})\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n###### Returns\n\nRedirects to `${DISPLAY_CODE_URL}?${Querystring.stringify({ id, phone: p })}` where `DISPLAY_CODE_URL` is the url of the ReactAPP to display the code on mobile\n\n### `POST` /users/phone/valid\n\nActivate the phone when user clicked on the SMS link. Send `PUSHER_EVENT` on success.\n\n* Remove phone from `PhoneSession`\n* Remove short-link from the `PhoneChecker`\n\n###### Payload\n\n```javascript\nJoi.object({\n    id: Joi.string().guid().required(),\n    phone: phoneRule.phone().mobile().required(),\n    session: Joi.string().guid().required(),\n    user_id: Joi.string().guid().required()\n})\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n###### Returns\n\nRedirects to `PHONE_SUCCESS_URL` that is the static url of success\n\n\n### `GET` /mfa\n\n* Get the code from `PhoneChecker`\n* Send `PUSHER_EVENT` on success with params `code: true and uuid`\n\n\n###### QueryParams\n\n```javascript\nJoi.object({\n    id: Joi.string().guid().required(),\n    phone: phoneRule.phone().mobile().required()\n})\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n###### Returns\n\n```json\n{\n    \"code\": \"SECRET_CODE\",\n    \"success\": true\n}\n```\n\n### `POST` /mfa/codes\n\n* Get the code from `PhoneChecker`\n* Send `PUSHER_EVENT` on success with params `code: true and uuid`\n\n\n###### Payload\n\n```javascript\nJoi.object({\n  code: Joi.string().required(),\n  uuid: Joi.string().guid().required(),\n  phone: phoneRule.phone().mobile().required()\n})\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n###### Returns\n\n```json\n{\n    \"success\": true,\n    \"can_retry\": true // or false when success is false\n}\n```\n\n### `POST` /users\n\n* Add card with minimum authorization\n* Create the user using user-api\n\n###### Handler: _Oyst_ _Session_\n\n###### Payload\n\n```javascript\nJoi.object({\n  address: address.required(),\n  billing_address: address.default(Joi.ref('address')),\n  email: Joi.string().email().required(),\n  first_name: Joi.string().required(),\n  language: Joi.string().length(2).optional(),\n  last_name: Joi.string().required()\n})\n```\n\nwhere `address` is\n\n```javascript\nJoi.object({\n  city: Joi.string().required(),\n  company_name: allowEmpty,\n  complementary: allowEmpty,\n  country: Joi.string().required(),\n  first_name: Joi.string().required(),\n  label: Joi.string().required(),\n  last_name: Joi.string().required(),\n  postcode: allowEmpty,\n  region: allowEmpty,\n  street: Joi.string().required()\n})\n```\n\nand `allowEmpty` is\n\n```javascript\nJoi.string().empty('').optional()\n```\n\nWhere `phoneRule` is the npm package `joi-phone-validator`\n\n###### Returns\n\n```json\n{\n    \"success\": true,\n    \"user\": {}\n}\n```\n\n### `POST` /notifications\n\n* Handle payment-api notifications\n\n**For now notification are not treated this is only usefull for the payment-api not to crashed**\n\n**TO FIX when order-api will be able to handle payment informations**\n\n###### Payload\n\n```javascript\nJoi.object({\n  live: Joi.boolean().required(),\n  notification: Joi.object().keys({\n    additional_data: Joi.object().optional(),\n    amount: Joi.object().keys({\n      currency: Joi.string().required(),\n      value: Joi.number().required()\n    }).required(),\n    event_code: Joi.string().required(),\n    event_date: Joi.date(),\n    is_3d: Joi.boolean().required(),\n    operations: Joi.array().items(Joi.string()).required(),\n    order_id: Joi.string().required(),\n    payment_id: Joi.string().guid().required(),\n    success: Joi.boolean().required(),\n  }).required()\n})\n```\n\n###### Returns\n\n`OK`\n\n\n","versions":{"1.1.0":{"name":"1click-api","version":"1.1.0","engines":{"node":">=6.0","npm":">=3.0"},"description":"API to handle 1click button","main":"index.js","scripts":{"heroku-prebuild":"node set-npmrc.js","build":"npm run clean && $(npm bin)/gulp build","clean":"$(npm bin)/gulp clean","dev":"$(npm bin)/gulp serve","lint":"tslint -c tslint.json '{src,__tests__}/**/*.ts'","postinstall":"npm run build","prestart":"./bin/prestart","pretest":"npm run reset && ./bin/prestart && npm run lint","posttest":"npm run reset","reset":"$(npm bin)/db-migrate reset","start":"node .","test":"jest --forceExit","tw":"npm test -- --watch"},"repository":{"type":"git","url":"git+https://github.com/oystparis/1click-api.git"},"author":{"name":"oyst team"},"license":"ISC","bugs":{"url":"https://github.com/oystparis/1click-api/issues"},"homepage":"https://github.com/oystparis/1click-api#readme","devDependencies":{"@types/hapi":"^16.0.6","@types/jest":"^19.2.3","@types/ramda":"0.0.9","@types/uuid":"^2.0.29","babel-cli":"^6.24.1","babel-core":"^6.24.1","babel-jest":"^20.0.0","babel-plugin-transform-async-to-generator":"^6.24.1","babel-plugin-transform-runtime":"^6.23.0","babel-polyfill":"^6.23.0","babel-preset-es2015":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-jest":"^20.0.0","babel-preset-stage-0":"^6.24.1","babel-register":"^6.24.1","babel-runtime":"^6.23.0","dotenv":"^4.0.0","faker":"^4.1.0","gulp":"^3.9.1","gulp-babel":"^6.1.2","gulp-content-to-variable":"^0.1.0","gulp-jest":"^1.0.0","gulp-load-plugins":"^1.5.0","gulp-nodemon":"^2.2.1","gulp-rimraf":"^0.2.1","gulp-tslint":"^8.0.0","gulp-typescript":"^3.1.6","jest":"^20.0.0","jest-cli":"^20.0.0","js-beautify":"^1.6.14","nock":"^9.0.13","sinon":"^2.3.5","ts-jest":"^20.0.0","ts-loader":"^2.0.3","ts-node":"^3.0.4","tslint":"^5.2.0","typescript":"^2.3.2","typescript-babel-jest":"^1.0.3","typescript-eslint-parser":"^3.0.0","typescript-standard":"^0.3.30","yargs":"^8.0.1"},"dependencies":{"@oyst/catalog-api":"^1.2.9","@oyst/env":"^0.3.5","@oyst/hapi-nats":"^0.3.2","@oyst/mfa":"^1.7.10","@oyst/phone-checker-lambda":"^1.0.3","@oyst/utils":"^1.10.6","@types/camelcase":"0.0.30","@types/camelcase-keys":"^4.0.0","@types/mobile-detect":"^1.2.29","airbrake":"^2.0.0","boom":"^4.3.1","camelcase":"^4.1.0","camelcase-keys":"^4.1.0","convert-keys":"^1.2.0","db-migrate":"^0.10.0-beta.20","db-migrate-pg":"^0.1.11","easysoap":"^1.0.6","hapi":"^16.1.1","hapi-api-version":"^1.3.0","hapi-health-check":"^1.1.0","hapi-i18n":"^1.0.4","hapi-namespace":"^1.0.3","hoek":"^4.1.1","i18n":"^0.8.3","inert":"^4.2.0","joi":"^10.4.1","joi-phone-validator":"^1.0.0","jsonwebtoken":"^7.4.0","massive":"^2.6.0","md5":"^2.2.1","mobile-detect":"^1.3.6","newrelic":"^1.39.0","param-case":"^2.1.1","ramda":"^0.23.0","redis":"^2.7.1","request":"^2.81.0","unirest":"^0.5.1","url-parse":"^1.1.9","uuid":"^3.0.1","vision":"^4.1.1"},"jest":{"moduleFileExtensions":["ts","tsx","js","json","node"],"transform":{"\\.(ts|tsx)$":"<rootDir>/preprocessor.js"},"testRegex":"/__tests__/.*\\.test.(ts|tsx|js)$","testEnvironment":"node","setupTestFrameworkScriptFile":"<rootDir>/jasmineConfig.js","setupFiles":["<rootDir>/jestSetup.js"],"coveragePathIgnorePatterns":["<rootDir>/jestSetup.js","<rootDir>/jasmineConfig.js","<rootDir>/src/lib/database.ts"],"unmockedModulePathPatterns":["<rootDir>/node_modules/jsonwebtoken"],"verbose":true},"standard":{"parser":"typescript-eslint-parser"},"gitHead":"d1f30e14dcb738830ef422820f53f74577edef5e","_id":"1click-api@1.1.0","_npmVersion":"5.0.3","_nodeVersion":"8.1.3","_npmUser":{"name":"nicolaschenet","email":"ironic51@gmail.com"},"dist":{"integrity":"sha512-umqbV8UhSVGHOJG9cgktA3Dk6/tmaBDAumqm11N5TKQ7t9wgbaRPPFMn31adsghkxi2jiqpXhGeeYcXJxJ3Dhw==","shasum":"be1fc181252a1f23233b9f5f508ff73799482658","tarball":"https://registry.npmjs.org/1click-api/-/1click-api-1.1.0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF1gCB1PRXuhHnpZHw0hVw6Ejs3gzFvFQ5noZHfp0mvqAiEA9LeYn1vI7QmG+DiCjUS/70s/q+hy480sFPXl7kG2asU="}]},"maintainers":[{"name":"nicolaschenet","email":"ironic51@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/1click-api-1.1.0.tgz_1499719830637_0.9175570132210851"}}},"homepage":"https://github.com/oystparis/1click-api#readme","repository":{"type":"git","url":"git+https://github.com/oystparis/1click-api.git"},"author":{"name":"oyst team"},"bugs":{"url":"https://github.com/oystparis/1click-api/issues"},"license":"ISC","readmeFilename":"README.md"}