{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"5813d06f-f2d8-41e9-aba6-d86710180a56","name":"Tango Networks Message Copy API","description":"# 📄 Tango Networks Message Copy API\n\nMessage Copy (formerly known as SMS Copy) is a feature of the Tango Networks Extend service that allows the UCaaS platform of a Tango Networks Extend partner, to receive a copy of SMS and MMS messages sent to/from mobile subscribers using an Extend SIM.\n\nMessage Copy is an API-only push service that provides a copy of the message metadata and content in the form of an HTTP(S) JSON POST to a partner’s receiving endpoint.\n\nSubscribers do not interact with the Message Copy service. The Message Copy feature is transparent to subscribers, and they are unaware of the service and whether it is enabled or disabled.\n\n## Scope\n\nThe Message Copy feature supports:\n\n- US and UK GPMN subscribers only\n    \n- All contents of the message copy are encoded in JSON format, using the UTF-8 character set\n    \n- SMS originations and terminations\n    \n    - person to person messaging\n        \n    - numeric and alphanumeric sender/recipient addresses\\*\n        \n- MMS originations and terminations:\n    \n    - person to person messaging\n        \n    - group messaging (sometimes called group chat)\n        \n    - Numeric sender/recipient addresses\n        \n- The Message Copy service is not a billable feature and has no impact on invoices\n    \n\n\\* While a mobile device can receive messages from an alphanumeric sender, a mobile can only originate a message to a numeric address.\n\nThe Message Copy feature does not support:\n\n- System messages - including Message Waiting indication messages, over-the-air SIM configuration messages, iMessage/FaceTime/iCloud activation messsages, and other binary messages\n    \n- Data-only messaging services - services like Apple's iMessage and or Android's RCS do not use the SMS or MMS signaling paths, as such, these data-only messages are not accessible by the Tango Networks Messaging infrastructure nor the Tango Networks Message Copy service.\n    \n\n---\n\n# ❓How does Message Copy work?\n\nIn order to use the Message Copy feature, the following Control Panel (CP) provisioning must be done first:\n\n- A distributor or reseller defines a **Recording Server** at the reseller level including the target endpoint’s URL for offloading.\n    \n- A distributor or reseller enables the Message Copy feature at the group level for all subscribers in a group.\n    \n\nOnce the Message Copy feature has been enabled for a group of subscribers the following recurring operations\n\n- Tango Networks Extend platform initiates an offload cycle periodically, no faster than once every 4 minutes.\n    \n- Each offload cycle sends up to 50 messages.\n    \n- Each message is offloaded as a single JSON formatted HTTP(S) POST to the Recording Server target URL.\n    \n- Once a messages is successfully offloaded to the customer URL, the message is deleted from the Tango Networks Extend platform servers.\n    \n- If a message fails to offload, it will be tried again at the next offload cycle.\n    \n\n# 🔑 Security\n\nWhile the Message Copy service supports both HTTP and HTTPS for its POST requests to a partner’s receiving endpoint, it is recommended that HTTPS be used to keep the contents of the copied messages secure in transit by using TLS encryption. HTTPS requires that the customer provide a proper valid public SSL certificate, issued by a CA.\n\n# 🔐 Authentication\n\nBearer authentication is an HTTP authentication scheme that involves security tokens called bearer tokens. These tokens are data filled against the provisioning **Message Copy Recording Server**. If provisioned every request includes the token as part of the Authentication Header.\n\n<img src=\"https://content.pstmn.io/235daaaa-971b-4f22-9507-9af328998128/YXV0aGhlYWRlci5wbmc=\" alt=\"Example:%20Authorization%20Header%20containing%20a%20Bearer%20Token\">\n\n# 🚦 Rate and usage limits\n\nA single Message Copy offload cycle can generate up to 50 HTTP(S) POST events to a partner's receiving endpoint. To lower the impact on the partner's receiving endpoint, the HTTP(S) POST events are sent serially, not in parallel. Tango Networks Extend platform initiates an offload cycle periodically, no faster than once every 4 minutes.\n\n# 🔖JSON Schema\n\nWhen a message is offloaded to the partner’s receiving endpoint, the message metadata and content are encoded using the following JSON schema:\n\n``` json\n\"smsEvent\" : [ {\n   \"direction\" : \"string\",         <\"mo\" or \"mt\">\n   \"startTime\" : \"string\",         <\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\">\n   \"segment\" : { <Optional>        - No longer included by Message Copy\n      \"id\" : \"string\",             - No longer included by Message Copy \n      \"number\" : int,              - No longer included by Message Copy\n      \"total\" : int                - No longer included by Message Copy\n   },\n   \"subscriberParty\" : {\n      \"domain\" : \"string\",         <domain of customer/tenant>\n      \"mobile\" : \"string\",         <subscriber international Mobile Number>\n      \"did\" : \"string\",            <subscriber international DID>\n      \"subrId\" : \"string\"          <subscriber Tango Extend ID>\n   },\n   \"otherParty\" : {\n      \"number\" : \"string\"          <Received number identifying other user>\n   },\n   \"message\" : \"string\"            <message content>\n   \"messageType\" : \"string\"        <\"sms\" or \"mms\">\n   \"messageContentType\" : \"string\" <content-type/sub-type of message content> \n} ]\n\n ```\n\n# 💻 Control Panel Provisioning\n\nThis section describes the Control Panel (CP) actions needed to enable the  \nMessage Copy feature.\n\n- CP Distributor or Reseller creates a Recording Server including the target URL for offloading.\\*\n    \n- CP Distributor or Reseller enables the Message Copy feature specifying the Recording Server.\n    \n\n\\* If the Recording Server URL is HTTPS, a valid signed certificate is required. Refer to [Security](#security) for more information.\n\n## Recording Server\n\nThe Recording Server defines a server name, the target country, and a URL  \nfor the customer’s offload server.\n\n1. Login to CP as either a distributor or reseller\n    \n2. Navigate to the reseller level\n    \n3. Hover over **Endpoints** and then click the **Recording Servers** link\n    \n    <img src=\"https://content.pstmn.io/9a50adca-9058-459e-8a93-39960252cad8/cmVjb3JkaW5nX3NlcnZlcnNfcGFnZS5wbmc=\" alt=\"Recording%20Server%20link%20at%20Reseller%20Level\">\n    \n4. Click the **New Server** button\n    \n5. Complete the **Add Server** information and click Save\n    \n\n<img src=\"https://content.pstmn.io/299f1768-10ca-4f1c-b267-bce1d3a442fc/YXV0aGtleS5wbmc=\" alt=\"Add%20Recording%20Server\" width=\"598\" height=\"262\">\n\n### Field Usage and Descriptions - Add Server\n\nAll of the following fields are mandatory:\n\n- **Name** - Provide a unique and identifiable name\n    \n- **HomeLoation** - Select Home Location of this recording server\n    \n- **Country** - Select Country\n    \n- **Server Type** - Select Message Copy\n    \n- **URL** - Provide a valid HTTPS or HTTP URL for the offloading target server\\*\n    \n- **Authentication Key** - Optional Bearer Authentication Token\n    \n\n\\* If the URL is HTTPS, a valid signed certificate is required. Refer to [Security](#security) for more information.\n\n## Message Copy\n\nMessage Copy enables (or disables) the Message Copy feature for all subscribers in a Group.\n\n1. As either a distributor or reseller in CP\n    \n2. Navigate to a Group\n    \n3. Hover over **Endpoints** and then click the **Edit Message Copy Settings** link\n    \n    <img src=\"https://content.pstmn.io/7520b209-2894-4d48-8166-d4f8f59e692f/ZWRpdF9tZXNzYWdlX2NvcHktYXRfZ3JvdXBfbGV2ZWwucG5n\" alt=\"Edit%20Message%20Copy%20Settings%20link%20at%20Group%20Level\">\n    \n4. Enable/Disable the feature, select the Recording Server, and click **Save**.\n    \n    <img src=\"https://content.pstmn.io/967f1d75-72f7-477e-a857-ef310daa45a9/ZW5hYmxlLW1lc3NhZ2UtY29weS5wbmc=\" alt=\"Enabling%20Message%20Copy\">\n    \n\n### Field Usage and Descriptions - Recording Server\n\nAll fields are mandatory:\n\n- **Send a copy of all messages for all subscribers in a Group** - (defaults to OFF) - Slide to ON to enable Message Copy for all subscriber in this Group\n    \n- **Message Copy Server** - Select the Recording Server from the drop-down menu.\\*\n    \n\n\\* If the Recording Server uses HTTPS, after a valid signed certificate has been loaded, the service is ready. For Recording Servers that use HTTP, no furtehr action is required. Refer to [Security](#security) for more information.\n\n# 🔩 Using Offloaded Messages\n\nThe Tango Networks Messaging Copy feature includes all necessary message metadata and content to enable a partner to recreate (and display) a copied message. This section describes how a partner can use the provided information to re-create and display a message locally.\n\nThe following fields are used for both SMS and MMS messages:\n\n- **direction** - This will indicate whether the message was an originated by the mobile `mo`, or terminated to the mobile `mt`\n    \n- **startTime** - This is the timestamp for when the message was processed.\n    \n- **mobile** - For an `mo`, this is the from party. For an `mt` this is the to party.\n    \n- **number** - For an `mo`, this is the to party. For an `mt` this is the from party.\\*\n    \n- **messageType** - This will be `sms` for SMS messages and `mms` for MMS messages.\n    \n\n\\* For a Group MMS message, only the first recipient is shown in the `number` field. The full list of recipients is included in the `message` contents. Refer to **Processing MMS Messages** for more information.\n\n## Processing SMS Messages\n\nTo recreate and display an SMS message, the following additional fields can be used:\n\n- **messageContentType** - This indicated the character set encoding of the message content. For `sms` messages, this will be `text/plain; charset=UTF-8`.\n    \n- **message** - This is the message content that should be displayed. The string can be directly copied as a UTF-8 string, which will automatically handle emoji and extended characters,\n    \n\nThe following is an example of an JSON file for an SMS origination:\n\n``` json\n{\n   \"smsEvent\" : [ {\n     \"direction\" : \"mo\",\n     \"startTime\" : \"2024-09-16T19:30:39.090+0000\",\n     \"subscriberParty\" : {\n     \"domain\" : \"software.tango-networks\",\n     \"mobile\" : \"19465559040\",\n     \"did\" : \"19465559040\",\n     \"subrId\" : \"s021157\"\n     },\n     \"otherParty\" : {\n       \"number\" : \"12145555273\"\n     },\n     \"message\" : \"This is SMS one 😀.\",\n     \"messageType\" : \"sms\",\n     \"messageContentType\" : \"text/plain; charset=UTF-8\"\n   } ]\n}\n\n ```\n\nProcessing the various offloaded JSON files can be done in many ways. It really depends on the requirements of the partner. Here is an simple bash shell script that will create a csv file for all offloaded SMS messages:\n\n``` bash\necho \"date,direction,extendmobile,otherparty,message\" > output.csv; \\\ngrep -l '\"messageType\" : \"sms\"' * | while read aFile ; do cat ${aFile} \\\n| jq -r '[.smsEvent[].startTime, .smsEvent[].direction, .smsEvent[].subscriberParty.mobile, .smsEvent[].otherParty.number, \n.smsEvent[].message] | @csv' ; done >> output.csv\n\n ```\n\nThe output.csv generated by the above script will look something like the following:\n\n```\ndate,direction,extendmobile,otherparty,message\n\"2024-09-16T19:30:39.090+0000\",\"mo\",\"19465559040\",\"12145555273\",\"This is SMS one 😀.\"\n\"2024-09-16T20:42:31.055+0000\",\"mt\",\"19465559040\",\"12145555273\",\"This is a a \"\"SMS termination\"\" message.\"\n\n ```\n\n## Processing MMS Messages\n\nTo recreate and display an MMS message, additional parsing and processing must be performed on the message content body. The display form of an MMS message is binary in nature (for example a PNG image a stream of binary data). The Tango Networks Extend infrastructure re-uses the text-based MM7 protocol encoding of an MMS message that comes from the MMSC Gateway. Specifically, MMS messages are encoded as 3GPP MMS Version 5.3.0 using MM7 Schema REL-5-MM7-1-2. This same format is re-used by the Messaging Copy feature.\n\nIn slightly less technical terms, the MMS message is stored in a multipart, text-only format, consisting of:\n\n- **SOAP envelope** - This is the first part, and is always present. It contains, among other things, the `To`, `From`, and `Subject` information of the MMS message.\\*\n    \n- **application/smil** - This part describes how a message should be displayed. Think of it as HTML doc that describes the layout of MMS.\n    \n- content part(s) - An MMS message can contain multiple content parts (e.g., a text part plus one more media files, or just multiple media files, etc.). There will always be at least one of the following in an MMS message:\n    \n    - **text/plain** - This is the text portion of the MMS content (i.e., whatever the person typed). This is an optional part.\n        \n    - **image/xxx** (xxx is a supported image format, e.g., png, jpeg, bmp, etc.) - This is a base64 encoded image file. There can be multiple images in a single MMS message.\n        \n    - **audio/xxx** (xxx is a supported audio format, e.g., wav, ogg, mp3, etc.) - This is a base64 encoded audio file. There can be multiple audio files in a single MMS message.\n        \n    - **text/x-vcard** (or **text/vcard**) - This is a vcard. If the vcard contains a photo, it will be encoded in base64.\n        \n\n\\* For Group MMS messages the entire list of recipients is present in the `Recipients` portion of the SOAP envelope.\n\nThe above list of content type/sub-types is not an exhaustive list, these are just common ones that are seen in a typcial MMS message.\n\nOne of the common use cases for partner post processing would be to see the image portion of an MMS message. Here is a series of bash commands that will extract and recreate images for all offloaded MMS messages:\n\n``` bash\ngrep -l '\"messageType\" : \"mms\"' * | \\\nwhile read aFile ; do \\\n  uuid=$(echo ${aFile} | cut -f1-5 -d'-') ; \\\n  grep -oP \"(?<=\\\"(message)\\\" : \\\")[^(,$)]+\" ${aFile} | awk '{gsub(/\\\\r\\\\n/,RS)} 1' > mm7_message.txt\n  csplit -s -f part -n 3 -z mm7_message.txt /-----mime-/ '{*}'\n  grep -le \"Content-Transfer-Encoding: base64\" part* | \\\n  while read aPart ; do \\\n    filename=$(grep -oP 'name=\\\\\"\\K[^\\\\]+' ${aPart}) ; \\\n    base64_data=$(awk '/^$/ {p=1; next} p' ${aPart} | grep -v '^-') ; \\\n    echo \"${base64_data}\" | base64 -d > \"${uuid}-${filename}\" ; \\\n    echo \"File extracted: ${uuid}-${filename}\" ; \\\n    /bin/rm part* ; /bin/rm mm7_message.txt ; \\\n  done ; \\\ndone\n\n ```\n\nThe output of the above script will look something like:\n\n```\nFile extracted: 2d0f8fdd-e91e-41d8-b341-04a3eaa8b417-image000000.png\n\n ```\n\nThis image file can then be opened in any image viewer (or browser) application to show:\n\n<img src=\"https://content.pstmn.io/f4533cd3-f484-43ad-a2ef-f70b2c36bcd1/aW1hZ2UwMDAwMDAucG5n\">\n\nThis is just an example of one way to process an offloaded MMS message. The bash schell commands could easily be wrapped in a script to add more descriptive output and to do enhanced message processing.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"2404338","team":257046,"collectionId":"5813d06f-f2d8-41e9-aba6-d86710180a56","publishedId":"2sAXqtZgGa","public":true,"publicUrl":"https://api-smscopy.tango-networks.com","privateUrl":"https://go.postman.co/documentation/2404338-5813d06f-f2d8-41e9-aba6-d86710180a56","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":""},{"name":"title","value":""}],"appearance":{"default":"light","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.10.0","publishDate":"2024-12-11T17:48:16.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":""},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/77341fa5d53538b935e87a0c70315a3e20cc757e5e6fa3b601d214f31464a0a9","favicon":"https://res.cloudinary.com/postman/image/upload/v1681152620/team/q3nv7qzb8nqzkvjxupce.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://api-smscopy.tango-networks.com/view/metadata/2sAXqtZgGa"}