{"id":28245084,"url":"https://github.com/multisafepay/pos-android-integration","last_synced_at":"2026-06-29T08:31:41.039Z","repository":{"id":91046099,"uuid":"581118163","full_name":"MultiSafepay/pos-android-integration","owner":"MultiSafepay","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-14T10:31:33.000Z","size":11797,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-14T12:24:54.338Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MultiSafepay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-12-22T10:17:46.000Z","updated_at":"2025-08-14T10:31:37.000Z","dependencies_parsed_at":"2025-02-14T13:26:28.202Z","dependency_job_id":"2a7be824-a92e-4b8a-9959-822a06a3a90a","html_url":"https://github.com/MultiSafepay/pos-android-integration","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/MultiSafepay/pos-android-integration","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MultiSafepay%2Fpos-android-integration","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MultiSafepay%2Fpos-android-integration/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MultiSafepay%2Fpos-android-integration/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MultiSafepay%2Fpos-android-integration/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MultiSafepay","download_url":"https://codeload.github.com/MultiSafepay/pos-android-integration/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MultiSafepay%2Fpos-android-integration/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34919882,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-19T08:14:58.532Z","updated_at":"2026-06-29T08:31:41.033Z","avatar_url":"https://github.com/MultiSafepay.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://www.multisafepay.com/img/multisafepaylogo.svg\" width=\"400px\"\u003e\n\u003c/p\u003e\n\n# POS Android Integration\n\n## Overview\n\nThis repository describes how to integrate a third-party Android application with the MultiSafepay Pay App using Android Intents (App-to-App communication).\n\n---\n\n## Integration Types\n\nThe Pay App supports two execution environments:\n\n* **SmartPOS** → Devices with payment kernel (e.g. Sunmi)\n* **Tap to Pay** → Android devices without kernel, using NFC\n\nBoth use the same App-to-App integration model.\n\n---\n\n## Pay App Packages\n\n* `com.multisafepay.pos.sunmi` → SmartPOS (kernel devices)\n* `com.multisafepay.pos.nokernels` → Tap to Pay (non-kernel devices)\n\n---\n\n## Selecting the Pay App\n\nUse the correct package depending on the device type.\n\n```java\nprivate String getMSPPackage(boolean isTapToPayDevice) {\n    if (isTapToPayDevice) {\n        return \"com.multisafepay.pos.nokernels\";\n    } else {\n        return \"com.multisafepay.pos.sunmi\";\n    }\n}\n```\n\n---\n\n## Manifest Configuration\n\n```xml\n\u003cmanifest\u003e\n\n    \u003cqueries\u003e\n        \u003cpackage android:name=\"com.multisafepay.pos.nokernels\" /\u003e\n        \u003cpackage android:name=\"com.multisafepay.pos.sunmi\" /\u003e\n    \u003c/queries\u003e\n\n\u003c/manifest\u003e\n```\n\n---\n\n## Callback Handling\n\n```java\n@Override\nprotected void onNewIntent(Intent intent) {\n    processMSPMiddlewareResponse(intent);\n    super.onNewIntent(intent);\n}\n\nprivate void processMSPMiddlewareResponse(@NonNull Intent intent) {\n    if (intent.hasExtra(\"status\")) {\n        int status = intent.getIntExtra(\"status\", 0);\n        String message = intent.getStringExtra(\"message\");\n        handleMiddlewareCallback(status, message);\n    }\n}\n\nprivate void handleMiddlewareCallback(int status, String message) {\n    switch (status) {\n        case 875:\n            receivedCallbackIntent(\"EXCEPTION \" + message);\n            break;\n        case 471:\n            receivedCallbackIntent(\"COMPLETED \" + message);\n            break;\n        case 17:\n            receivedCallbackIntent(\"CANCELLED \" + message);\n            break;\n        case 88:\n            receivedCallbackIntent(\"DECLINED \" + message);\n            break;\n    }\n}\n\nprivate void receivedCallbackIntent(String message) {\n    Intent intent = new Intent(this, PaymentActivity.class);\n    intent.putExtra(\"message\", message);\n    intent.putExtra(\"description\", \"pass data to this Activity\");\n    startActivity(intent);\n}\n```\n\n---\n\n## Payment Flows\n\n### 1. Standard (Legacy) Flow\n\n#### Order Items\n\n```java\nJSONArray jsonArray = new JSONArray();\n\ntry {\n    JSONObject item1 = new JSONObject();\n    item1.put(\"name\", \"Product 1\");\n    item1.put(\"unit_price\", \"0.10\");\n    item1.put(\"quantity\", \"1\");\n    item1.put(\"merchant_item_id\", \"749857\");\n    item1.put(\"tax\", \"3.90\");\n\n    JSONObject item2 = new JSONObject();\n    item2.put(\"name\", \"Product 2\");\n    item2.put(\"unit_price\", \"0.20\");\n    item2.put(\"quantity\", \"1\");\n    item2.put(\"merchant_item_id\", \"749857\");\n    item2.put(\"tax\", \"1.40\");\n\n    jsonArray.put(item1);\n    jsonArray.put(item2);\n\n} catch (JSONException e) {\n    e.printStackTrace();\n}\n```\n\n---\n\n#### Sending Payment Intent\n\n```java\nboolean isTapToPayDevice = false; // Implement your own device detection\nString packageName = getMSPPackage(isTapToPayDevice);\n\nIntent intent = getPackageManager().getLaunchIntentForPackage(packageName);\n\nif (intent != null) {\n\n    if (!isTapToPayDevice) {\n        intent.setClassName(packageName,\n            \"com.multisafepay.pos.middleware.IntentActivity\");\n    }\n\n    // amount must be long and expressed in minor units (for example: cents)\n    long amountInCents = amount;\n\n    intent.putExtra(\"items\", jsonArray.toString());\n    intent.putExtra(\"order_id\", getOrderId());\n    intent.putExtra(\"order_description\", \"info about the order\");\n    intent.putExtra(\"currency\", \"EUR\");\n    intent.putExtra(\"amount\", amountInCents);\n    intent.putExtra(\"package_name\", getPackageName());\n\n    startActivity(intent);\n}\n```\n\n---\n\n### 2. E-commerce Flow\n\n#### Order Items\n\n```java\nJSONArray jsonArray = new JSONArray();\n\ntry {\n    JSONObject socks = new JSONObject();\n    socks.put(\"name\", \"Socks\");\n    socks.put(\"description\", \"One pair of black socks\");\n    socks.put(\"merchant_item_id\", \"001-M\");\n    socks.put(\"unit_price\", 0.105785124);\n    socks.put(\"quantity\", 3);\n    socks.put(\"tax_table_selector\", \"21_percent\");\n\n    JSONObject shipping = new JSONObject();\n    shipping.put(\"name\", \"Shipping\");\n    shipping.put(\"description\", \"Domestic shipping (zone 1)\");\n    shipping.put(\"merchant_item_id\", \"msp-shipping\");\n    shipping.put(\"unit_price\", 0.15);\n    shipping.put(\"quantity\", 1);\n\n    jsonArray.put(socks);\n    jsonArray.put(shipping);\n\n} catch (JSONException e) {\n    e.printStackTrace();\n}\n```\n\n---\n\n#### Sending Payment Intent\n\n```java\nboolean isTapToPayDevice = false; // Implement your own device detection\nString packageName = getMSPPackage(isTapToPayDevice);\n\nIntent intent = getPackageManager().getLaunchIntentForPackage(packageName);\n\nif (intent != null) {\n\n    if (!isTapToPayDevice) {\n        intent.setClassName(packageName,\n            \"com.multisafepay.pos.middleware.IntentActivity\");\n    }\n\n    setCheckoutOptions(intent);\n\n    // amount must be long and expressed in minor units (for example: cents)\n    long amountInCents = amount;\n\n    intent.putExtra(\"items\", jsonArray.toString());\n    intent.putExtra(\"order_id\", getOrderId());\n    intent.putExtra(\"description\", \"info about the order\");\n    intent.putExtra(\"currency\", \"EUR\");\n    intent.putExtra(\"amount\", amountInCents);\n    intent.putExtra(\"reference\", \"Ref-\" + System.currentTimeMillis());\n    intent.putExtra(\"auto_close\", false);\n    intent.putExtra(\"package_name\", getPackageName());\n\n    startActivity(intent);\n}\n```\n\n---\n\n### Checkout Options\n\n```java\nprivate void setCheckoutOptions(Intent intent) {\n    try {\n        JSONObject checkoutOptions = new JSONObject();\n\n        checkoutOptions.put(\"validate_cart\", true);\n\n        JSONObject taxTables = new JSONObject();\n        checkoutOptions.put(\"tax_tables\", taxTables);\n\n        JSONObject defaultTaxTable = new JSONObject();\n        defaultTaxTable.put(\"rate\", 0);\n        taxTables.put(\"default\", defaultTaxTable);\n\n        intent.putExtra(\"checkout_options\", checkoutOptions.toString());\n\n    } catch (JSONException e) {\n        e.printStackTrace();\n    }\n}\n```\n\n---\n\n## Unreferenced Refund Flow\n\n```java\nprivate void sendRefundIntent(long amountInCents, boolean isTapToPayDevice) {\n\n    String packageName = getMSPPackage(isTapToPayDevice);\n\n    Intent intent = getPackageManager()\n            .getLaunchIntentForPackage(packageName);\n\n    if (intent != null) {\n\n        if (!isTapToPayDevice) {\n            intent.setClassName(\n                    packageName,\n                    \"com.multisafepay.pos.middleware.IntentActivity\"\n            );\n        }\n\n        intent.putExtra(\"order_id\", \"REFUND_\" + System.currentTimeMillis());\n        intent.putExtra(\"amount\", amountInCents);\n        intent.putExtra(\"refund\", true);\n        intent.putExtra(\"package_name\", getPackageName());\n\n        startActivity(intent);\n    }\n}\n```\n\n---\n\n## Tap to Pay Notes\n\nTap to Pay uses the same App-to-App integration model as SmartPOS, but the entry point is different.\n\n* Same Intent structure\n* Same parameters\n* Same callback handling\n\nFor **SmartPOS** (`com.multisafepay.pos.sunmi`), the payment flow is started directly via:\n\n`com.multisafepay.pos.middleware.IntentActivity`\n\nFor **Tap to Pay** (`com.multisafepay.pos.nokernels`), the app should be launched using the package launcher intent:\n\n`getLaunchIntentForPackage(\"com.multisafepay.pos.nokernels\")`\n\nIn this case, the app handles the incoming intent through its launcher flow before navigating to the payment screen.\n\nImportant:\n* Use `setClassName(..., \"com.multisafepay.pos.middleware.IntentActivity\")` only for SmartPOS\n* Do not force `IntentActivity` for Tap to Pay\n* `amount` must be sent as `long` in minor units\n* `package_name` must be the package name of the third-party app that should receive the callback intent","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultisafepay%2Fpos-android-integration","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmultisafepay%2Fpos-android-integration","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultisafepay%2Fpos-android-integration/lists"}