{"id":20516235,"url":"https://github.com/aftership/aftership-sdk-java","last_synced_at":"2025-05-09T08:33:06.189Z","repository":{"id":805259,"uuid":"20639988","full_name":"AfterShip/aftership-sdk-java","owner":"AfterShip","description":"The Java SDK of AfterShip API","archived":true,"fork":false,"pushed_at":"2024-07-24T10:49:16.000Z","size":639,"stargazers_count":15,"open_issues_count":0,"forks_count":29,"subscribers_count":48,"default_branch":"master","last_synced_at":"2025-03-21T09:47:56.305Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AfterShip.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2014-06-09T08:47:10.000Z","updated_at":"2024-07-24T10:49:35.000Z","dependencies_parsed_at":"2023-11-23T09:23:22.372Z","dependency_job_id":"4d54c878-59e9-49f0-af35-174ff3a0ac6d","html_url":"https://github.com/AfterShip/aftership-sdk-java","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AfterShip%2Faftership-sdk-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AfterShip%2Faftership-sdk-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AfterShip%2Faftership-sdk-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AfterShip%2Faftership-sdk-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AfterShip","download_url":"https://codeload.github.com/AfterShip/aftership-sdk-java/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253217284,"owners_count":21873059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-11-15T21:27:37.382Z","updated_at":"2025-05-09T08:33:05.826Z","avatar_url":"https://github.com/AfterShip.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Deprecation notice: New Version Available\n\nThis version of the SDK has been deprecated and replaced with the newly reconstructed SDK.\n\nFor the latest API features and improved integration, please visit our updated repository at https://github.com/AfterShip/tracking-sdk-java and follow the provided instructions.\n\n\n# aftership-sdk-java\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.slack.api/slack-api-client.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:com.aftership%20a:aftership-sdk)\n[![AfterShip SDKs channel](https://aftership-sdk-slackin.herokuapp.com/badge.svg)](https://aftership-sdk-slackin.herokuapp.com/)\n[![Build Status](https://api.travis-ci.org/chenjunbiao/aftership-sdk-java.svg?branch=v2)](https://travis-ci.org/github/chenjunbiao/aftership-sdk-java)\n\nThe Java SDK of `AfterShip API`, please see API documentation in: https://www.aftership.com/docs/api/4\n\nRequirements:\n\n- JDK 1.8 or superior.\n\n## Installation\n\n### Maven\n\n```text\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.aftership\u003c/groupId\u003e\n  \u003cartifactId\u003eaftership-sdk\u003c/artifactId\u003e\n  \u003cversion\u003e4.0.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Gradle\n\n```text\nimplementation \"com.aftership:aftership-sdk:4.0.1\"\n```\n\n\n## Quick Examples\n\n### Main Steps\n\nThe following code example shows the `three main steps` to use aftership-sdk-java:\n\n1. Create `AfterShip` Object.\n\n```java\nAftershipOption option = new AftershipOption();\noption.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n\nAfterShip afterShip = new AfterShip(\"YOUR_API_KEY\", option);\n\n// if add aes sign\nAfterShip afterShip = new AfterShip(\"YOUR_API_KEY\", AuthenticationType.AES, \"YOUR_API_SECRET\", option);\n```\n\n2. Get the Endpoint Interface and call the method, then return the object.\n\n```java \nCourierList courierList = afterShip.getCourierEndpoint().listCouriers();\n```\n\n3. Handling `Data` or `AftershipException`  or `RateLimit`\n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip = new AfterShip(\"YOUR_API_KEY\", option);\n  CourierList courierList = afterShip.getCourierEndpoint().listCouriers();\n  // using data\n  System.out.println(courierList);\n} catch (SdkException | RequestException e) {\n  // handle SdkException, RequestException\n  System.out.println(e.getType());\n  System.out.println(e.getMessage());\n  System.out.println(e.getData());\n} catch (ApiException e) {\n  // handle ApiException\n  if (e.isTooManyRequests()) {\n    // Analyze RateLimit when TooManyRequests occur\n    System.out.println(e.getRateLimit().getReset());\n    System.out.println(e.getRateLimit().getLimit());\n    System.out.println(e.getRateLimit().getRemaining());\n    return;\n  }\n  System.out.println(e.getType());\n  System.out.println(e.getCode());\n  System.out.println(e.getMessage());\n}\n```\n## Troubleshoot\n### Received fatal alert: handshake_failure\n\n\u003e The SSL Protocol of `api.aftership.com` is TLSV1.2, and the Cipher is AES256-SHA.\nIt is a known issue due to this reason:\n\n#### The Cipher Suite of your JVM not include `TLS_AES_256_GCM_SHA384`\n\nYou can check the CipherSuite according to this [article](https://help.mulesoft.com/s/article/How-to-list-the-Cipher-Suite-of-JVM-and-the-Cipher-used-on-a-handshake-with-endpoint)\n\nExecute `java CipherSuite api.aftership.com:443`, under normal circumstances, it should output\n```\nCipherSuite used on the handshake:TLS_AES_256_GCM_SHA384\n```\n\nOtherwise, you should check the cipherSuite of your JVM.\n1. Make sure `crypto.policy=unlimited` is effective in the jre/lib/securityjava.security\n2. If your JDK version number is lower than 7u171 or 8u161, please follow this [oracle article](https://docs.oracle.com/cd/E60058_01/PDF/8.0.6.x/8.0.6.0.0/AG_HTML/Enabling_Unlimited_Cryptographic_Policy_for_Java.htm) to download JCE.\n\n#### SSL protocol of your client is lower than TLSV1.2\n\nYou can check the protocol version used during the SSL negotiation by capturing transport packet\n\n## Error Handling\n\nThere are 4 kinds of exception\n\n- AftershipException\n- SdkException\n- RequestException\n- ApiException\n\nError object of this SDK contain fields:\n\n- `type` - **Require** - type of the error, **please handle each error by this field**\n\n- `message` - **Optional** - detail message of the error\n\n- `code` - **Optional** - error code for API Error\n\n  You can find tips for Aftership's error codes in here: https://www.aftership.com/docs/tracking/quickstart/request-errors\n\n  If it's Aftership's API Error, get code to confirm the cause of the error:\n\n  ```java\n  catch (AftershipException e){\n    if(e.isApiError()){\n      System.out.println(e.getCode());\n    }\n  }\n  ```\n\n- `data` - **Optional** - data lead to the error\n\n  The debug Data is a `Map\u003cString, Object\u003e` object that can get the call parameters. \n\n  The following data may be available:\n\n  ```java \n  catch (AftershipException e){\n    System.out.println(e.getData());\n    // or\n    System.out.println(e.getData().get(DEBUG_DATA_KEY_REQUEST_CONFIG));\n    System.out.println(e.getData().get(DEBUG_DATA_KEY_REQUEST_HEADERS));\n    System.out.println(e.getData().get(DEBUG_DATA_KEY_REQUEST_DATA));\n    System.out.println(e.getData().get(DEBUG_DATA_KEY_RESPONSE_BODY));\n  }\n  ```\n### AftershipException\n\nAftershipException is the base class for all exception classes and can capture it for uniform handling.\n\nSee the `Rate Limiter` section for TooManyRequests in ApiException.\n\n```java\ncatch (AftershipException e){\n  if(e.isApiError()){\n    System.out.println(e.getCode());\n    if(e.isTooManyRequests() \u0026\u0026 e instanceof ApiException){\n      System.out.println(((ApiException)e).getRateLimit());\n    }\n  }\n  System.out.println(e.getType());\n  System.out.println(e.getMessage());\n  System.out.println(e.getData());\n}\n```\n\n### SdkException\n\nException return by the SDK instance, mostly invalid param type when calling constructor or endpoint method\nerror.Type is one of [ErrorType](https://github.com/AfterShip/aftership-sdk-java/blob/v2/aftership-sdk/src/main/java/com/aftership/sdk/error/ErrorType.java)\n**Throw** by the SDK instance\n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip =\n      new AfterShip(null, option);\n} catch (SdkException e) {\n  System.out.println(e.getMessage());\n}\n\n/* ConstructorError: Invalid API key; type: ConstructorError */\n```\n\n**Throw** by endpoint method\n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip =\n      new AfterShip(\"YOUR_API_KEY\", option);\n  afterShip.getTrackingEndpoint().getTracking(\"\", null);\n} catch (SdkException e) {\n  System.out.println(e.getMessage());\n}\n\n/* ConstructorError: Required tracking id; type: ConstructorError */\n```\n\n### RequestException\n\nError return by the `request` module \n`error.Type` could be `HandlerError`, etc.  \n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip =\n      new AfterShip(\"YOUR_API_KEY\", option);\n  afterShip.getTrackingEndpoint().getTracking(\"abc\", null);\n} catch (RequestException e) {\n  System.out.println(e.getMessage());\n}\n\n/* null; type: HandlerError; */\n```\n\n### ApiException\n\nError return by the AfterShip API  \n`error.Type` should be the same as https://www.aftership.com/docs/api/4/errors\n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip =\n      new AfterShip(\"YOUR_API_KEY\", option);\n  afterShip.getTrackingEndpoint().getTracking(\"abc\", null);\n} catch (ApiException e) {\n  System.out.println(e.getMessage());\n}\n\n/* The value of `id` is invalid.; type: BadRequest; code: 4015; */\n```\n\n### Rate Limiter\n\nTo understand AfterShip rate limit policy, please see `limit` session in https://www.aftership.com/docs/api/4\n\nYou can get the recent rate limit by `ApiException.getRateLimit()`. \n\n```java\ntry {\n  AftershipOption option = new AftershipOption();\n  option.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\n  AfterShip afterShip =\n    new AfterShip(\"YOUR_API_KEY\", option);\n  afterShip.getCourierEndpoint().listCouriers();\n} catch (SdkException | RequestException e) {\n  System.out.println(e.getType());\n} catch (ApiException e) {\n  if (e.isTooManyRequests()) {\n    System.out.println(e.getRateLimit().getReset());\n    System.out.println(e.getRateLimit().getLimit());\n    System.out.println(e.getRateLimit().getRemaining());\n  }\n}\n// 1589869159\n// 10\n// 9\n```\n\n### Timeout\n\nWhen creating an Aftership object, you can define the timeout time for http requests, Of course, use the default value of 20 seconds when not set. The unit is milliseconds.\n\n```java \nAftershipOption option = new AftershipOption();\noption.setEndpoint(\"https://api.aftership.com/tracking/2023-10\");\noption.setCallTimeout(10 * 1000);\noption.setConnectTimeout(10 * 1000);\noption.setReadTimeout(10 * 1000);\noption.setWriteTimeout(10 * 1000);\nAfterShip afterShip = new AfterShip(SampleUtil.getApiKey(), option);\n```\n\n### Retry\nRetry policy implemented using OKHttp interceptor. Allows to customize the delay interval, maximum retry interval, and number of retries; implements an exponential backoff delay strategy.\n#### 1 RetryInterceptor\n```java\npublic class RetryInterceptor implements Interceptor {\n\n  private long initialDelay;              // Initial retry delay in milliseconds\n  private long maxDelay;                  // Maximum retry delay in milliseconds\n  private int maxRetries;                 // Maximum number of retries\n  private double backoffMultiplier;       // Exponential backoff multiplier. Should ideally be greater than 1.\n  private double jitterFactor;            // Jitter factor for randomized delay\n  private List\u003cRetryCondition\u003e retryConditions;  // Customizable retry condition\n\n}\n```\n\n- `initialDelay`: The initial retry interval. Default is `500ms`.\n- `maxDelay`: The maximum delay. After reaching the maximum delay, subsequent retries will use the same value. Default is `18s` (default timeout is 20s).\n- `maxRetries`: The maximum number of retries. Default is `10`.\n- `backoffMultiplier`: The exponential backoff multiplier. After each retry attempt, the retry interval will be multiplied by this value, resulting in exponential growth of delays. Default is `1.6`.\n- `jitterFactor`: The jitter factor. Adds positive or negative jitter to calculated exponential backoff delay, helping to distribute retry requests and reduce server load. Default is `0.2`.\n- `retryConditions`: Custom retry conditions allow customers to define their own retry criteria. Default is to retry on exceptions or when response status code is `≥500`.\n\n#### 2 backoff()\nCalculates the exponential backoff delay based on the number of retry attempts.\n\n```java\npublic class RetryInterceptor implements Interceptor {\n  /**\n   * Calculates the exponential backoff delay for the specified retry attempt number, using the configured\n   * backoff multiplier and maximum delay, and adds randomized jitter to the delay.\n   *\n   * @param retries The current retry attempt number.\n   * @return The calculated delay before the next retry attempt, in milliseconds.\n   */\n  private long backoff(int retries) {\n    // Calculate exponential backoff delay: initialDelay * (backoffMultiplier ^ retries)\n    long delay = (long) (initialDelay * Math.pow(backoffMultiplier, retries));\n    // Calculate jitter: jitterFactor * delay * random number in [-1, 1) range\n    double jitter = jitterFactor * delay * (Math.random() - 0.5) * 2;\n    // Add the exponential backoff delay and jitter to get the final delay\n    long finalDelay = (long) (delay + jitter);\n\n    // Ensure the final delay does not exceed the maximum delay\n    if (finalDelay \u003e maxDelay) {\n      finalDelay = maxDelay;\n    }\n\n    return finalDelay;\n  }\n```\n\nAssuming retries=10, initialDelay=500, backoffMultiplier=1.6, jitterFactor=0.2, and maxDelay=18,000; the time intervals required for each retry are as follows:\n\n| retries | delay |\n| --- | --- |\n| 1 | 586 |\n| 2 | 787 |\n| 3 | 1342 |\n| 4 | 2304 |\n| 5 | 3219 |\n| 6 | 4592 |\n| 7 | 7293 |\n| 8 | 12020 |\n| 9 | 18000 |\n| 10 | 18000 |\n\n#### 3 Example\n```java\npublic class RetrySample {\n  public static void main(String[] args) {\n    AftershipOption option = SampleUtil.getAftershipOption();\n\n    RetryOption retryOption = new RetryOption();\n    retryOption.setRetryDelay(500);\n    retryOption.setRetryMaxDelay(18 * 1000L);\n    retryOption.setRetryCount(10);\n    retryOption.setRetryConditions(Arrays.asList((\n      (response, exception) -\u003e exception != null || (response != null \u0026\u0026 response.code() \u003e= 500))));\n\n    option.setRetryOption(retryOption);\n    AfterShip afterShip = new AfterShip(SampleUtil.getApiKey(), option);\n  }\n}\n```\n- Retry interval: 500ms\n- Maximum retry interval: 18s\n- Number of retries: 10\n- Retry conditions: exception != null || (response != null \u0026\u0026 response.code() \u003e= 500)\n- backoffMultiplier and jitterFactor are set to 1.6 and 0.2 respectively by default\n\n\n### Shutdown\n\nWe recommend using only one AfterShip object to request interfaces of the API, and calling the `shutdown` method if you want to completely clean up all network resources when you shut down your system. In other cases, not running shutdown method has no effect.\n\n```java\ntry {\n  afterShip.getCourierEndpoint().listCouriers();\n} catch (RequestException | ApiException e) {\n  e.printStackTrace();\n} finally {\n  try {\n    afterShip.shutdown();\n  } catch (IOException e) {\n    e.printStackTrace();\n  }\n}\n```\n\n## Examples\n\n### /couriers\n\n- #### listCouriers [GET /couriers]\n\n```java \ntry {\n  CourierList courierList = afterShip.getCourierEndpoint().listCouriers();\n  System.out.println(courierList.getTotal());\n  System.out.println(courierList.getCouriers().get(0).getName());\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### listAllCouriers [GET /couriers/all]\n\n```java \ntry {\n  CourierList courierList = afterShip.getCourierEndpoint().listAllCouriers();\n  System.out.println(courierList.getTotal());\n  System.out.println(courierList.getCouriers());\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### detectCouriers [POST /couriers/detect]\n\n```java\nCourierDetectTracking tracking = new CourierDetectTracking();\ntracking.setTrackingNumber(\"906587618687\");\nCourierDetectRequest courierDetectRequest = new CourierDetectRequest(tracking);\n\ntry {\n  CourierDetectList courierDetectList =\n    afterShip.getCourierEndpoint().detectCouriers(courierDetectRequest.getTracking());\n\n  System.out.println(courierDetectList.getTotal());\n  System.out.println(courierDetectList.getCouriers());\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n### /trackings\n\n- #### createTracking [POST /trackings]\n\n```java\nNewTracking newTracking = new NewTracking();\n// slug from listAllCouriers()\nnewTracking.setSlug(new String[] {\"acommerce\"});\nnewTracking.setTrackingNumber(\"1234567890\");\nnewTracking.setTitle(\"Title Name\");\nnewTracking.setSmses(new String[] {\"+18555072509\", \"+18555072501\"});\nnewTracking.setEmails(new String[] {\"email@yourdomain.com\", \"another_email@yourdomain.com\"});\nnewTracking.setOrderId(\"ID 1234\");\nnewTracking.setOrderIdPath(\"http://www.aftership.com/order_id=1234\");\nnewTracking.setCustomFields(\n  new HashMap\u003cString, String\u003e(2) {\n    {\n      put(\"product_name\", \"iPhone Case\");\n      put(\"product_price\", \"USD19.99\");\n    }\n  });\nnewTracking.setLanguage(\"en\");\nnewTracking.setOrderPromisedDeliveryDate(\"2019-05-20\");\nnewTracking.setDeliveryType(\"pickup_at_store\");\nnewTracking.setPickupLocation(\"Flagship Store\");\nnewTracking.setPickupNote(\n  \"Reach out to our staffs when you arrive our stores for shipment pickup\");\n\ntry {\n  Tracking tracking = afterShip.getTrackingEndpoint().createTracking(newTracking);\n  System.out.println(tracking);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n\n\n- #### deleteTracking [DELETE /trackings/:slug/:tracking_number]\n\n```java \nString id = \"u2qm5uu9xqpwykaqm8d5l010\";\ntry {\n  Tracking tracking = afterShip.getTrackingEndpoint().deleteTracking(id);\n  System.out.println(tracking);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### getTrackings [GET /trackings]\n\n```java \nGetTrackingsParams optionalParams = new GetTrackingsParams();\noptionalParams.setFields(\"title,order_id\");\noptionalParams.setLang(\"china-post\");\noptionalParams.setLimit(10);\n\ntry {\n  PagedTrackings pagedTrackings = afterShip.getTrackingEndpoint().getTrackings(optionalParams);\n  System.out.println(pagedTrackings);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### getTracking [GET /trackings/:slug/:tracking_number]\n\n  - Get by id:\n\n    ```java\n    String id = \"l389dilsluk9ckaqmetr901y\";\n    try {\n      Tracking tracking = afterShip.getTrackingEndpoint().getTracking(id, null);\n      System.out.println(tracking);\n    } catch (AftershipException e) {\n      System.out.println(e.getMessage());\n    }\n    ```\n    \n  - Get by slug and tracking_number:\n  \n    ```java \n    String slug = \"acommerce\";\n    String trackingNumber = \"1234567890\";\n    try {\n      Tracking tracking =\n      afterShip\n        .getTrackingEndpoint()\n      .getTracking(new SlugTrackingNumber(slug, trackingNumber), null);\n      System.out.println(tracking);\n    } catch (AftershipException e) {\n      System.out.println(e.getMessage());\n    }\n    ```\n  \n- #### updateTracking [PUT /trackings/:slug/:tracking_number]\n\n```java\nString id = \"vebix4hfu3sr3kac0epve01n\";\nUpdateTracking updateTracking = new UpdateTracking();\nupdateTracking.setTitle(\"title123\");\n\ntry {\n  Tracking tracking1 = afterShip.getTrackingEndpoint().updateTracking(id, updateTracking);\n  System.out.println(tracking1);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### reTrack [POST /trackings/:slug/:tracking_number/retrack]\n\n```java\nString id = \"l389dilsluk9ckaqmetr901y\";\ntry {\n  Tracking tracking = afterShip.getTrackingEndpoint().reTrack(id);\n  System.out.println(tracking);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### markAsCompleted [POST /trackings/:slug/:tracking_number/mark-as-completed]\n\n```java \nString id = \"5b7658cec7c33c0e007de3c5\";\ntry {\n  Tracking tracking =\n    afterShip.getTrackingEndpoint().markAsCompleted(id, new CompletedStatus(ReasonKind.LOST));\n  System.out.println(tracking);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n### /last_checkpoint\n\n- #### getLastCheckpoint [GET /last_checkpoint/:slug/:tracking_number]\n\n```java\nString id = \"vebix4hfu3sr3kac0epve01n\";\nGetCheckpointParam optionalParam = new GetCheckpointParam();\noptionalParam.setFields(FieldsKind.combine(FieldsKind.TAG));\noptionalParam.setLang(LangKind.CHINA_EMS);\n\ntry {\n  LastCheckpoint lastCheckpoint =\n    afterShip.getCheckpointEndpoint().getLastCheckpoint(id, optionalParam);\n  System.out.println(lastCheckpoint.getSlug());\n  System.out.println(lastCheckpoint.getTrackingNumber());\n  System.out.println(lastCheckpoint.getCheckpoint());\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n### /notifications\n\n- #### getNotification [GET /notifications/:slug/:tracking_number]\n\n```java \nString id = \"vebix4hfu3sr3kac0epve01n\";\ntry {\n  Notification notification = afterShip.getNotificationEndpoint().getNotification(id);\n  System.out.println(notification);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### addNotification [POST /notifications/:slug/:tracking_number/add]\n\n```java\nString id = \"vebix4hfu3sr3kac0epve01n\";\nNotification addNotification = new Notification();\naddNotification.setSmses(new String[] {\"+85261236123\", \"Invalid Mobile Phone Number\"});\n\ntry {\n  Notification notification =\n    afterShip.getNotificationEndpoint().addNotification(id, addNotification);\n  System.out.println(notification);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n- #### removeNotification [POST /notifications/:slug/:tracking_number/remove]\n\n```java \nString id = \"vebix4hfu3sr3kac0epve01n\";\nNotification removeNotification = new Notification();\nremoveNotification.setEmails(new String[] {\"invalid EMail @ Gmail. com\"});\nremoveNotification.setSmses(new String[] {\"+85261236123\"});\ntry {\n  Notification notification =\n    afterShip.getNotificationEndpoint().removeNotification(id, removeNotification);\n  System.out.println(notification);\n} catch (AftershipException e) {\n  System.out.println(e.getMessage());\n}\n```\n\n\n\n## Notes\n\n- #### When specifying a tracking, the `id` is equivalent to the `slug and tracking_number`.\n\n```java \ngetTracking(\"l389dilsluk9ckaqmetr901y\", null);\n```\n\n```java \ngetTracking(new SlugTrackingNumber(\"acommerce\", \"1234567890\"), null);\n```\n\n## License\nCopyright (c) 2015-2022 Aftership  \nLicensed under the MIT license.\n\n​\t\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faftership%2Faftership-sdk-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faftership%2Faftership-sdk-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faftership%2Faftership-sdk-java/lists"}