{"_id":"594a7812106f84001a4fd79b","project":"54eb50e5615ffc1900305a16","version":{"_id":"54eb63b859b1172100334fae","project":"54eb50e5615ffc1900305a16","forked_from":"54eb63a1867e1917009b711d","__v":28,"createdAt":"2015-02-23T17:30:32.501Z","releaseDate":"2015-02-23T17:30:32.501Z","categories":["54eb63b959b1172100334faf","54eb63b959b1172100334fb0","54eb63b959b1172100334fb1","54eb63b959b1172100334fb2","54ed8dd4ab373e2300f50eae","54ed99b2ab373e2300f50ede","55153a6de68daa2f00cff838","551546edbc466623002afe72","5515472ac28d6125001b8884","55154749c28d6125001b8885","555d9b4106dfec0d00d38ea7","5613e06e433e5735007c7708","5624bbb785a31117001c5403","56669e857cc81e0d00253f8e","568b8d837a42220d00498311","56a632277ef6620d00e2f18a","56d8147c3eb4dd0b00201aac","57a9ce2fac6db30e000d7efd","57a9cf4e944ea60e00dc3f74","58172386715dce0f00da4aa0","582dc59ee1b8692300c0dd03","589b19b4fec2730f0082e040","58b04a023529383900a759b5","58b92d1598157a0f004869bf","592e7685c58275000f20174f","59392839e376d4002f8a0474","59393064e376d4002f8a05a1","5947ae0d4005e2000f3a4fec","594a74df1d1de5001ab3517a","5954bc387a147f001b918915","59b8eeeb707542001076d3b6"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1"},"category":{"_id":"594a74df1d1de5001ab3517a","project":"54eb50e5615ffc1900305a16","version":"54eb63b859b1172100334fae","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2017-06-21T13:30:07.315Z","from_sync":false,"order":0,"slug":"new-getting-started","title":"Getting started"},"user":"54eb4fdedf7add210007b29b","__v":1,"parentDoc":null,"updates":["59721ee63295a20020298653"],"next":{"pages":[],"description":""},"createdAt":"2017-06-21T13:43:46.325Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"For maximum compatibility and durability of your integration application, it is recommended that you follow the best practices listed on this page. Not all of the notes apply to every integration. For example, parsing `json` is not relevant for applications requesting API responses in an `xml` format. However, it is a good practice to keep the below points in mind.\n\n## Backwards compatibility\n\nInfobip API evolves over time. We work hard to add new functionalities and improve existing ones with new features. In doing so, we will maintain backward compatibility according to a couple of rules. Abiding by those rules will ensure that your integration continues to work properly with any future API improvements while allowing you to easily take advantage of those new features.\n\n### Adding new fields to existing resources\n\nOne of the ways that we will use to introduce new features to the existing API endpoints is through adding new properties to existing request and/or response models. For example:\n\n```\nOriginal response model:\n{\n    \"status\": \"OK\",\n    \"statusId\": 1\n}\n\nExtended response model:\n{\n    \"status\": \"OK\",\n    \"statusId\": 1,\n    \"statusDescription\": \"All went well, no additional actions required\"\n}\n```\n\nWhen adding properties to request models we will always ensure that the field is optional so that all of the existing integrations continue to work without problems. \n\nRegarding the properties in response models, however, you should ensure that your parsing implementation does not break when it encounters unspecified properties. That way you will not have to update your code every time a new feature is added to the API. At the same time, if you choose to use the new feature updating your code will be simplified since you will only need to parse one new property. \n\n### JSON property order\n\n[Json specification](http://www.json.org/) does not guarantee the order of name/value pairs in objects, so your `json` parsing implementation should not depend on it either. In practice it that means that the following `json` objects are considered to be identical:\n\n```\nExample object:\n{\n    \"status\": \"OK\",\n    \"statusId\": 1\n}\n\nEquivalent object:\n{\n    \"statusId\": 1,\n    \"status\": \"OK\"\n}\n```\n\nAPI implementation may interchangeably return any of the above example objects and they should be treated identically by the client code. Fortunately, if `json` parsing is delegated to your language's native functionality or one of the established parsing libraries this should already be handled properly by those implementations.\n\n### Date formats\n\nAPI will generally return dates in a predefined and uniform format. Consult dedicated documentation page for details on a specific endpoint. The format used by a default is:\n\n```\nyyyy-MM-dd'T'HH:mm:ss.SSSZ\n```\n\nNote that the format encodes, and requires a time zone information. This means that the two seemingly different date time strings actually represent the same point in time:\n\n```\n2017-07-20T06:47:45.777+0000\n2017-07-20T07:47:45.777+0100\n```\n\nWhen parsing dates received from the API you should take the timezone into account. It is best practice to convert the string received from the API into your language's native representation of the moment in time. Then it can be processed and displayed to your users a time zone and format of your choosing. The important note is not to expect that date times returned from the API will always be in some predefined time zone. Instead, you should use the returned time zone information.\n\n## Preventing errors\n\nBesides ensuring that your application will continue to be compatible with the future developments on the API it is also important to keep it free of bugs. To help you with that here are a couple of common problems that should be taken into account.\n\n### Request body content types\n\nAs discussed in a dedicated [documentation page](/docs/content-types), every request that contains message body data should contain Content-Type header. Supported content types are `application/json` and `application/xml`. In each case, the body data that you send in your request should match the supplied Content-Type header and be valid.\n\n#### `json` content\n\nIf you choose to use `json` make sure that you serialize your data into [valid `json` objects](http://www.json.org/). Specifically, watch out for string values. They should not contain double quote characters (`\"`) as including them would mark an end of a string. If double quotes are needed make sure they are escaped with a backslash (`\\`). Furthermore, make sure that name/value pairs in your json objects are separated by commas (`,`). If you opt to use some of the standard serialization libraries this should all be implemented already.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n\\t\\\"stringProperty\\\": \\\"properly \\\\\\\"quoted\\\\\\\" string value\\\",\\n  \\\"numberProperty\\\": 47,\\n  \\\"booleanProperty\\\": true,\\n  \\\"nullProperty\\\": null\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Valid json\"\n    },\n    {\n      \"code\": \"{\\n\\t\\\"stringProperty\\\": \\\"properly \\\"quoted\\\" string value\\\"\\n  \\\"numberProperty\\\": 47\\n  \\\"booleanProperty\\\": true\\n  nullProperty: null\\n}\",\n      \"language\": \"text\",\n      \"name\": \"Invalid json\"\n    }\n  ]\n}\n[/block]\n#### `xml` content\n\nIf you are using `xml` also make sure that your objects are properly serialized into valid `xml`. Specifically, check that you are closing all of your tags and that you are doing so in the correct order. Also, note that the tags are case sensitive. Again, well established `xml` serialization library or native language function should take care of all of this.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<request>\\n  <outerProperty>\\n    <nestedProperty>Some Value</nestedProperty>\\n  </outerProperty>\\n  <flatProperty>47</flatProperty>\\n  <emptyProperty/>\\n</request>\",\n      \"language\": \"xml\",\n      \"name\": \"Valid xml\"\n    },\n    {\n      \"code\": \"<request>\\n  <outerProperty>\\n    <nestedProperty>Some Value</outerProperty>\\n  </nestedProperty>\\n  <flatProperty>47\\n  <emptyProperty>\\n</request>\",\n      \"language\": \"text\",\n      \"name\": \"InvalidXml\"\n    }\n  ]\n}\n[/block]\n### Deprecated standards\n\nWith the passing of time industry standards can become deprecated. The prime example of this is the usage of the SHA-1 hashing function in SSL certificates. As noted in the [security and authorization documentation section](https://dev.infobip.com/v1/docs/security-and-authorization), it is strongly recommended to connect to our API using the HTTPS protocol. Since SHA-1 has been deprecated and support for it is being removed from modern technology stacks and applications, our API is signed by certificates created using newer algorithms. In order to recognize it, your stack should use them as well.\n\n## Handling errors\n\nEven in a normal integration operation, it is expected to encounter some error responses from the API. In cases when an error occurs we will attempt to fill the API response with a recognizable and self-explanatory message. In those cases, it is advisable to have your code analyze the API response and react to them in an appropriate manner.\n\n### HTTP response codes\n\nYou can find the list of all HTTP response codes with their meaning explained [here](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). We will strive to return the appropriate status code to every request. Examining the returned status code is the first thing you can do to determine how to react to an API response.\n\nGenerally, any status in the '200's range (from '200' up to '299') is considered to be successful and no additional reaction is needed. \n\nResponses with a status code in the '400's range ('400' to '499') indicate that there was something wrong with your request. Immediately sending the exact same request again will result in the same error so it is not advisable. Instead, you can analyze the specific status returned and adapt accordingly. If for example, the status '400 (Bad request)' is returned, you should double check your Content-type header, check that your request body data is properly serialized and that the data sent to the API corresponds to the specified request model from the dedicated API endpoint documentation page. On the other hand, receiving the status '404 (Not found)' means that either the requested API endpoint or the exact resource do not exist. In this case, double check the API endpoint path defined in the dedicated documentation page.\n\nStatus codes in the '500's range ('500' to '599') signal that the request is valid but an error occurred on the API side. Depending on the specific status the error might be temporary so retrying the same request may yield different results.\n\n### Throttling\n\nOne of the specific errors that can occur with your requests is a throttling error. It will generally be denoted by an HTTP status code '429 (Too Many Requests)' and it happens when you make too many requests to a specific endpoint within a predefined amount of time.\n\nInfobip API does not have a single throttling rule for all endpoints. Instead, some of them might have dedicated rules. To find specific ones revert to the dedicated documentation pages. For example, you can make as many send SMS requests as you wish. Those endpoints are considered to be used for traffic and have no limitations. On the other hand, fetching sent SMS logs is an administrative endpoint that should be used for bulk reporting. Because of that, there is a limit on the number of requests allowed in a time window. Any subsequent get logs requests will receive the status code of '429' and will not be carried until enough time passes.\n\nIn case one of your API requests ends up being throttled, you could hold on for a little while and then retry it again. However, be mindful of retrying too many times, since you could cause even more requests to be throttled. When implementing retry logic make sure to include a limit on the number of retries and monitor the overall number of throttled requests. If too many of your requests end up being throttled you might be using the API in an unsupported way.","excerpt":"","slug":"api-integration-best-practices","type":"basic","title":"Integration best practices"}

Integration best practices


For maximum compatibility and durability of your integration application, it is recommended that you follow the best practices listed on this page. Not all of the notes apply to every integration. For example, parsing `json` is not relevant for applications requesting API responses in an `xml` format. However, it is a good practice to keep the below points in mind. ## Backwards compatibility Infobip API evolves over time. We work hard to add new functionalities and improve existing ones with new features. In doing so, we will maintain backward compatibility according to a couple of rules. Abiding by those rules will ensure that your integration continues to work properly with any future API improvements while allowing you to easily take advantage of those new features. ### Adding new fields to existing resources One of the ways that we will use to introduce new features to the existing API endpoints is through adding new properties to existing request and/or response models. For example: ``` Original response model: { "status": "OK", "statusId": 1 } Extended response model: { "status": "OK", "statusId": 1, "statusDescription": "All went well, no additional actions required" } ``` When adding properties to request models we will always ensure that the field is optional so that all of the existing integrations continue to work without problems. Regarding the properties in response models, however, you should ensure that your parsing implementation does not break when it encounters unspecified properties. That way you will not have to update your code every time a new feature is added to the API. At the same time, if you choose to use the new feature updating your code will be simplified since you will only need to parse one new property. ### JSON property order [Json specification](http://www.json.org/) does not guarantee the order of name/value pairs in objects, so your `json` parsing implementation should not depend on it either. In practice it that means that the following `json` objects are considered to be identical: ``` Example object: { "status": "OK", "statusId": 1 } Equivalent object: { "statusId": 1, "status": "OK" } ``` API implementation may interchangeably return any of the above example objects and they should be treated identically by the client code. Fortunately, if `json` parsing is delegated to your language's native functionality or one of the established parsing libraries this should already be handled properly by those implementations. ### Date formats API will generally return dates in a predefined and uniform format. Consult dedicated documentation page for details on a specific endpoint. The format used by a default is: ``` yyyy-MM-dd'T'HH:mm:ss.SSSZ ``` Note that the format encodes, and requires a time zone information. This means that the two seemingly different date time strings actually represent the same point in time: ``` 2017-07-20T06:47:45.777+0000 2017-07-20T07:47:45.777+0100 ``` When parsing dates received from the API you should take the timezone into account. It is best practice to convert the string received from the API into your language's native representation of the moment in time. Then it can be processed and displayed to your users a time zone and format of your choosing. The important note is not to expect that date times returned from the API will always be in some predefined time zone. Instead, you should use the returned time zone information. ## Preventing errors Besides ensuring that your application will continue to be compatible with the future developments on the API it is also important to keep it free of bugs. To help you with that here are a couple of common problems that should be taken into account. ### Request body content types As discussed in a dedicated [documentation page](/docs/content-types), every request that contains message body data should contain Content-Type header. Supported content types are `application/json` and `application/xml`. In each case, the body data that you send in your request should match the supplied Content-Type header and be valid. #### `json` content If you choose to use `json` make sure that you serialize your data into [valid `json` objects](http://www.json.org/). Specifically, watch out for string values. They should not contain double quote characters (`"`) as including them would mark an end of a string. If double quotes are needed make sure they are escaped with a backslash (`\`). Furthermore, make sure that name/value pairs in your json objects are separated by commas (`,`). If you opt to use some of the standard serialization libraries this should all be implemented already. [block:code] { "codes": [ { "code": "{\n\t\"stringProperty\": \"properly \\\"quoted\\\" string value\",\n \"numberProperty\": 47,\n \"booleanProperty\": true,\n \"nullProperty\": null\n}", "language": "json", "name": "Valid json" }, { "code": "{\n\t\"stringProperty\": \"properly \"quoted\" string value\"\n \"numberProperty\": 47\n \"booleanProperty\": true\n nullProperty: null\n}", "language": "text", "name": "Invalid json" } ] } [/block] #### `xml` content If you are using `xml` also make sure that your objects are properly serialized into valid `xml`. Specifically, check that you are closing all of your tags and that you are doing so in the correct order. Also, note that the tags are case sensitive. Again, well established `xml` serialization library or native language function should take care of all of this. [block:code] { "codes": [ { "code": "<request>\n <outerProperty>\n <nestedProperty>Some Value</nestedProperty>\n </outerProperty>\n <flatProperty>47</flatProperty>\n <emptyProperty/>\n</request>", "language": "xml", "name": "Valid xml" }, { "code": "<request>\n <outerProperty>\n <nestedProperty>Some Value</outerProperty>\n </nestedProperty>\n <flatProperty>47\n <emptyProperty>\n</request>", "language": "text", "name": "InvalidXml" } ] } [/block] ### Deprecated standards With the passing of time industry standards can become deprecated. The prime example of this is the usage of the SHA-1 hashing function in SSL certificates. As noted in the [security and authorization documentation section](https://dev.infobip.com/v1/docs/security-and-authorization), it is strongly recommended to connect to our API using the HTTPS protocol. Since SHA-1 has been deprecated and support for it is being removed from modern technology stacks and applications, our API is signed by certificates created using newer algorithms. In order to recognize it, your stack should use them as well. ## Handling errors Even in a normal integration operation, it is expected to encounter some error responses from the API. In cases when an error occurs we will attempt to fill the API response with a recognizable and self-explanatory message. In those cases, it is advisable to have your code analyze the API response and react to them in an appropriate manner. ### HTTP response codes You can find the list of all HTTP response codes with their meaning explained [here](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). We will strive to return the appropriate status code to every request. Examining the returned status code is the first thing you can do to determine how to react to an API response. Generally, any status in the '200's range (from '200' up to '299') is considered to be successful and no additional reaction is needed. Responses with a status code in the '400's range ('400' to '499') indicate that there was something wrong with your request. Immediately sending the exact same request again will result in the same error so it is not advisable. Instead, you can analyze the specific status returned and adapt accordingly. If for example, the status '400 (Bad request)' is returned, you should double check your Content-type header, check that your request body data is properly serialized and that the data sent to the API corresponds to the specified request model from the dedicated API endpoint documentation page. On the other hand, receiving the status '404 (Not found)' means that either the requested API endpoint or the exact resource do not exist. In this case, double check the API endpoint path defined in the dedicated documentation page. Status codes in the '500's range ('500' to '599') signal that the request is valid but an error occurred on the API side. Depending on the specific status the error might be temporary so retrying the same request may yield different results. ### Throttling One of the specific errors that can occur with your requests is a throttling error. It will generally be denoted by an HTTP status code '429 (Too Many Requests)' and it happens when you make too many requests to a specific endpoint within a predefined amount of time. Infobip API does not have a single throttling rule for all endpoints. Instead, some of them might have dedicated rules. To find specific ones revert to the dedicated documentation pages. For example, you can make as many send SMS requests as you wish. Those endpoints are considered to be used for traffic and have no limitations. On the other hand, fetching sent SMS logs is an administrative endpoint that should be used for bulk reporting. Because of that, there is a limit on the number of requests allowed in a time window. Any subsequent get logs requests will receive the status code of '429' and will not be carried until enough time passes. In case one of your API requests ends up being throttled, you could hold on for a little while and then retry it again. However, be mindful of retrying too many times, since you could cause even more requests to be throttled. When implementing retry logic make sure to include a limit on the number of retries and monitor the overall number of throttled requests. If too many of your requests end up being throttled you might be using the API in an unsupported way.