API Consumption, Adoption, Integration

Made Simple via DX Kits

Trusted By

"In 3 month, across the 7 SDKs that we generate, we've been able to save $20,000 in development costs"

Why APIMATIC?

Forget About APIs and Free up Developers’ time

Consolidate all of your API endpoints and accelerate your development lifecycle. With APIMatic, you can create, customize, and manage SDKs with a simple, cloud-based solution.

Automate with Continuous Delivery & Integration

With APIMATIC, you can easily enable CI/CD for any scale and speed up your development and testing. APIMATIC takes care of the API updates and breaking changes. You can also use our Jenkins/CircleCI/Travis ready SDKs to quickly integrate SDK generation within your CI cycle. Learn more.

Works with Your Programming Stack

You can generate SDKs for languages including C#, Java, Ruby, Python, iOS, and Android. Plus, it doesn’t require you to do any coding. We take care of generating, testing, and ongoing management of the SDKs. APIMatic also works with leading CI/CD tools and plugins like CircleCI, Smartbear.

Use Test scripts and Sample code

APIMATIC provides test scripts and sample code, so you can automatically test as the new SDKs are generated. You can also offer sample code examples to your development teams to reduce any friction relating to SDK adoption. To learn more, see you docs.

In Our Cloud or Your Datacenter

Our customers are startups and large enterprises. APIMatic is built from the ground up to be to be flexible. You can generate SDKs using APIMatic’s secure cloud-based platform, or easily deploy APIMatic in your own datacenter as a private cloud.

We’ll Support You At Every Step

Whether you need help in planning your API and SDK architecture or just testing the SDKs after updating API endpoints, you can rely on our team of experts and get answers quickly. Click here to contact.

Always Update-to-date and fully-tested SDKs

Don’t be overwhelmed by the breaking changes, support requests for out-of-date and missing SDKs. With APIMatic, you can easily run your CI/CD development processes because your SDKs are automatically up-to-date. You can also use our test cases along with your generated SDKs to perform unit and integration testing. This enables early detection of any bugs and inconsistencies between software tiers as your update your APIs. Click here to contact.

Curious to see real-world example?

Check out the SDKs for Uber API below

Sample SDK Code: Python

                                
def get_products(self,
				 latitude,
				 longitude):
	"""Does a GET request to /products.
	Args:
		latitude (float): Latitude component of location.
		longitude (float): Longitude component of location.

	Returns:
		list of Product: Response from the API. An array of products
	"""

	# The base uri for api requests
	_query_builder = Configuration.BASE_URI

	# Prepare query string for API call
	_query_builder += "/products"

	# Process optional query parameters
	_query_parameters = {
		"latitude": latitude,
		"longitude": longitude
	}
	
	# Validate and preprocess url
	_query_url = APIHelper.clean_url(_query_builder)

	# Prepare headers
	_headers = {
		"user-agent": "APIMATIC 2.0",
		"accept": "application/json",
		"Authorization": "Bearer " + Configuration.o_auth_access_token
	}

	# Prepare the API call.
	_http_request = self.http_client.get(_query_url, headers=_headers, query_parameters=_query_parameters)

	# Invoke the on before request HttpCallBack if specified
	if self.http_call_back != None:
		self.http_call_back.on_before_request(_http_request)

	# Invoke the API call  to fetch the response.
	_response = self.http_client.execute_as_string(_http_request)

	# Invoke the on after response HttpCallBack if specified
	if self.http_call_back != None:
		self.http_call_back.on_after_response(_response)

	# Endpoint error handling using HTTP status codes.
	if _response.status_code == 500:
		raise APIException("Unexpected error", 500, _response.raw_body)

	# Global error handling using HTTP status codes.
	self.validate_response(_response)    

	# Return appropriate type
	return APIHelper.json_deserialize(_response.raw_body, Product.from_dictionary)
                                            
                                        
                                
/**
 * Product Types
 * @param  double     $latitude      Required parameter: Latitude component of location.
 * @param  double     $longitude     Required parameter: Longitude component of location.
 * @return mixed response from the API call
 * @throws APIException Thrown if API call fails
 */
public function getProducts (
			$latitude,
			$longitude) 
{
	//the base uri for api requests
	$_queryBuilder = Configuration::$BASEURI;
	
	//prepare query string for API call
	$_queryBuilder = $_queryBuilder.'/products';

	//process optional query parameters
	APIHelper::appendUrlWithQueryParameters($_queryBuilder, array (
		'latitude'  => $latitude,
		'longitude' => $longitude,
	));

	//validate and preprocess url
	$_queryUrl = APIHelper::cleanUrl($_queryBuilder);

	//prepare headers
	$_headers = array (
		'user-agent'    => 'APIMATIC 2.0',
		'Accept'        => 'application/json',
		'Authorization' => sprintf('Bearer %1$s', Configuration::$oAuthAccessToken)
	);

	//call on-before Http callback
	$_httpRequest = new HttpRequest(HttpMethod::GET, $_headers, $_queryUrl);
	if($this->getHttpCallBack() != null) {
		$this->getHttpCallBack()->callOnBeforeRequest($_httpRequest);            
	}

	//and invoke the API call request to fetch the response
	$response = Request::get($_queryUrl, $_headers);

	//call on-after Http callback
	if($this->getHttpCallBack() != null) {
		$_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body);
		$_httpContext = new HttpContext($_httpRequest, $_httpResponse);
		
		$this->getHttpCallBack()->callOnAfterRequest($_httpContext);            
	}

	//Error handling using HTTP status codes
	if ($response->code == 500) {
		throw new APIException('Unexpected error', 500, $response->body);
	}

	else if (($response->code < 200) || ($response->code > 206)) { //[200,206] = HTTP OK
		throw new APIException("HTTP Response Not OK", $response->code, $response->body);
	}

	$mapper = $this->getJsonMapper();

	return $mapper->mapArray($response->body, array(), new Models\Product());
}
                                        
                                        
                            
/// <summary>
/// Product Types
/// </summary>
/// <param name="latitude">Required parameter: Latitude component of location.</param>
/// <param name="longitude">Required parameter: Longitude component of location.</param>
/// <return>Returns the List<Product> response from the API call</return>
public async Task<List<Product>> GetProductsAsync(double latitude, double longitude)
{
	//the base uri for api requestss
	string _baseUri = Configuration.BaseUri;

	//prepare query string for API call
	StringBuilder _queryBuilder = new StringBuilder(_baseUri);
	_queryBuilder.Append("/products");

	//process optional query parameters
	APIHelper.AppendUrlWithQueryParameters(_queryBuilder, new Dictionary<string, object>()
	{
		{ "latitude", latitude },
		{ "longitude", longitude }
	});


	//validate and preprocess url
	string _queryUrl = APIHelper.CleanUrl(_queryBuilder);

	//append request with appropriate headers and parameters
	var _headers = new Dictionary<string,string>()
	{
		{ "user-agent", "APIMATIC 2.0" },
		{ "accept", "application/json" }
	};
	_headers.Add("Authorization", string.Format("Bearer {0}", Configuration.OAuthAccessToken));

	//prepare the API call request to fetch the response
	HttpRequest _request = ClientInstance.Get(_queryUrl,_headers);

	//invoke request and get response
	HttpStringResponse _response = (HttpStringResponse) await ClientInstance.ExecuteAsStringAsync(_request);
	HttpContext _context = new HttpContext(_request,_response);

	//Error handling using HTTP status codes
	if (_response.StatusCode == 500)
		throw new APIException(@"Unexpected error", _context);

	//handle errors defined at the API level
	base.ValidateResponse(_response, _context);

	try
	{
		return APIHelper.JsonDeserialize<List<Product>>(_response.Body);
	}
	catch (Exception _ex)
	{
		throw new APIException("Failed to parse the response: " + _ex.Message, _context);
	}
}
                                    
                                    
                            
/**
 * Product Types
 * @param {double} latitude    Required parameter: Latitude component of location.
 * @param {double} longitude    Required parameter: Longitude component of location.
 *
 * @return {promise<array>}
 */
getProducts : function(latitude, longitude){

	//Create promise to return
	var _deffered= $q.defer();
	
	//prepare query string for API call
	var _baseUri = Configuration.BASEURI
	var _queryBuilder = _baseUri + "/products";
	
	//Process query parameters
	_queryBuilder = APIHelper.appendUrlWithQueryParameters(_queryBuilder, {
		"latitude" : latitude,
		"longitude" : longitude
	});

	//validate and preprocess url
	var _queryUrl = APIHelper.cleanUrl(_queryBuilder);
	
	//prepare headers
	var _headers = {
		"accept" : "application/json",
		"Authorization" : "Bearer " + Configuration.oAuthAccessToken
	};

	//prepare and invoke the API call request to fetch the response
	var _config = {
		method : "GET",
		queryUrl : _queryUrl,
		headers: _headers,
	};
	
	var _response = HttpClient(_config);
	
	//process response
	_response.then(function(_result){
		_deffered.resolve(_result.body);
	},function(_result){
		//Error handling for custom HTTP status codes
		if (_result.code == 500) {
			_deffered.reject(APIHelper.appendContext({errorMessage: "Unexpected error", errorCode: 500, errorResponse: _result.message},_result.getContext()));
		} else {
			_deffered.reject(APIHelper.appendContext({errorMessage:"HTTP Response Not OK", errorCode: _result.code, errorResponse: _result.message},_result.getContext()));
		}
	});
	
	return _deffered.promise;
}
                                    
                                    
                            
# Product Types
# @param [Float] latitude Required parameter: Latitude component of location.
# @param [Float] longitude Required parameter: Longitude component of location.
# @return List of Product response from the API call
def get_products(latitude, 
				 longitude)
  # the base uri for api requests
  _query_builder = Configuration.base_uri.dup

  # prepare query string for API call
  _query_builder << '/products'

  # process optional query parameters
  _query_builder = APIHelper.append_url_with_query_parameters _query_builder, {
	'latitude' => latitude,
	'longitude' => longitude
  }

  # validate and preprocess url
  _query_url = APIHelper.clean_url _query_builder

  # prepare headers
  _headers = {
	'user-agent' => 'APIMATIC 2.0',
	'accept' => 'application/json',
	'Authorization' => 'Bearer %s' % (Configuration.o_auth_access_token)
  }

  # Create the HttpRequest object for the call
  _http_request = @http_client.get _query_url, headers: _headers
  
  # Call the on_before_request callback
  @http_call_back.on_before_request(_http_request) if @http_call_back

  # Invoke the API call and get the response
  _response = @http_client.execute_as_string(_http_request)

  # Call the on_after_response callback
  @http_call_back.on_after_response(_response) if @http_call_back

  # Endpoint error handling using HTTP status codes.
  if _response.status_code == 500
	raise APIException.new 'Unexpected error', 500, _response.raw_body
  end

  # Global error handling using HTTP status codes.
  validate_response(_response)

  # Return appropriate response type
  decoded = APIHelper.json_deserialize(_response.raw_body)
  return decoded.map{|element| Product.from_hash(element)}
end
                                    
                                    
                            
/**
 * Product Types
 * @param    latitude    Required parameter: Latitude component of location.
 * @param    longitude    Required parameter: Longitude component of location.
 * @return    Returns the void response from the API call 
 */
public void getProductsAsync(
			final double latitude,
			final double longitude,
			final APICallBack<List<Product>> callBack
) {
	//the base uri for api requests
	String _baseUri = Configuration.baseUri;

	//prepare query string for API call
	StringBuilder _queryBuilder = new StringBuilder(_baseUri);
	_queryBuilder.append("/products");

	//process query parameters
	APIHelper.appendUrlWithQueryParameters(_queryBuilder, new HashMap<String, Object>() {
		private static final long serialVersionUID = 4900859286829085857L;
		{
				put( "latitude", latitude );
				put( "longitude", longitude );
		}});
	//validate and preprocess url
	String _queryUrl = APIHelper.cleanUrl(_queryBuilder);

	//load all headers for the outgoing API request
	Map<String, String> _headers = new HashMap<String, String>() {
		private static final long serialVersionUID = 5580125263158353135L;
		{
				put( "user-agent", "APIMATIC 2.0" );
				put( "accept", "application/json" );
				put( "Authorization", String.format("Bearer %1$s", Configuration.oAuthAccessToken) );
		}
	};

	//prepare and invoke the API call request to fetch the response
	final HttpRequest _request = getClientInstance().get(_queryUrl, _headers, null);

	//invoke the callback before request if its not null
	if (getHttpCallBack() != null)
	{
		getHttpCallBack().OnBeforeRequest(_request);
	}

	//invoke request and get response
	Runnable _responseTask = new Runnable() {
		public void run() {
			//make the API call
			getClientInstance().executeAsStringAsync(_request, new APICallBack<HttpResponse>() {
				public void onSuccess(HttpContext _context, HttpResponse _response) {
					try {

						//invoke the callback after response if its not null
						if (getHttpCallBack() != null)	
						{
							getHttpCallBack().OnAfterResponse(_context);
						}

						//Error handling using HTTP status codes
						int _responseCode = _response.getStatusCode();
						if (_responseCode == 500)
							throw new APIException("Unexpected error", _context);

						//handle errors defined at the API level
						validateResponse(_response, _context);

						//extract result from the http response
						String _responseBody = ((HttpStringResponse)_response).getBody();
						List<Product> _result = APIHelper.deserialize(_responseBody,
													new TypeReference<List<Product>>(){});

						//let the caller know of the success
						callBack.onSuccess(_context, _result);
					} catch (APIException error) {
						//let the caller know of the error
						callBack.onFailure(_context, error);
					} catch (IOException ioException) {
						//let the caller know of the caught IO Exception
						callBack.onFailure(_context, ioException);
					} catch (Exception exception) {
						//let the caller know of the caught Exception
						callBack.onFailure(_context, exception);
					}
				}
				public void onFailure(HttpContext _context, Throwable _error) {
					//invoke the callback after response if its not null
					if (getHttpCallBack() != null)	
						{
						getHttpCallBack().OnAfterResponse(_context);
					}

					//let the caller know of the failure
					callBack.onFailure(_context, _error);
				}
			});
		}
	};

	//execute async using thread pool
	APIHelper.getScheduler().execute(_responseTask);
}
                                    
                                    
                            
/**
* Product Types
* @param    latitude    Required parameter: Latitude component of location.
* @param    longitude    Required parameter: Longitude component of location.
* @return	Returns the void response from the API call */
- (void) getProductsAsyncWithLatitude:(double) latitude
                longitude:(double) longitude
                completionBlock:(CompletedGetProducts) onCompleted
{
    //the base uri for api requests
    NSString* _baseUri = [NSString stringWithString: (NSString*) Configuration_BaseUri];

    //prepare query string for API call
    NSMutableString* _queryBuilder = [NSMutableString stringWithString: _baseUri]; 
    [_queryBuilder appendString: @"/products"];

    //process optional query parameters
    [APIHelper appendUrl: _queryBuilder withQueryParameters: @{
                    @"latitude": [NSNumber numberWithDouble: latitude],
                    @"longitude": [NSNumber numberWithDouble: longitude]
                }];

    //validate and preprocess url
    NSString* _queryUrl = [APIHelper cleanUrl: _queryBuilder];

    //preparing request headers
    NSMutableDictionary* _headers = [[NSMutableDictionary alloc] initWithDictionary: @{
        @"user-agent": @"APIMATIC 2.0",
        @"accept": @"application/json",
        @"Authorization": [NSString stringWithFormat:@"Bearer %@", Configuration_OAuthAccessToken]
    }];

    //Remove null values from header collection in order to omit from request
    [APIHelper removeNullValues: _headers];


    //prepare the request and fetch response  
    HttpRequest* _request = [[self clientInstance] get: ^(HttpRequest* _request) 
    { 
        [_request setQueryUrl: _queryUrl]; //set request url        
        [_request setHeaders: _headers]; //set request headers

    }];

    //use the instance of the http client to make the actual call
    [[self clientInstance]
     executeAsString: _request
     success: ^(id _context, HttpResponse *_response) {
         //Error handling using HTTP status codes
         NSError* _statusError = nil;

         //Error handling using HTTP status codes 
         if (_response.statusCode == 500)
             _statusError = [[APIError alloc] initWithReason: @"Unexpected error"
                                                    andCode: _response.statusCode
                                                    andData: _response.rawBody];

         else if((_response.statusCode < 200) || (_response.statusCode > 206)) //[200,206] = HTTP OK
             _statusError = [[APIError alloc] initWithReason: @"HTTP Response Not OK"
                                                    andCode: _response.statusCode
                                                    andData: _response.rawBody];

         if(_statusError != nil)
         {
             //announce completion with failure due to HTTP status code checking
             onCompleted(NO, _context, nil, _statusError);
         }
         else
         {
             //return _response to API caller
             NSString* _strResult = [(HttpStringResponse*)_response body];
             NSArray<Product> * _result = (NSArray<Product>*) [Product arrayOfModelsFromDictionaries:
                [APIHelper jsonDeserializeArray: _strResult] error: nil];

 
             //announce completion with success
             onCompleted(YES, _context, _result, nil);
         }
     } failure:^(id _context, NSError *_error) {
 
         //announce completion with failure
         onCompleted(NO, _context, nil, _error);
     }];
}
                                    
                                    
                            
/**
 * Product Types
 * @param    latitude    Required parameter: Latitude component of location.
 * @param    longitude    Required parameter: Longitude component of location.
 * @return    Returns the void response from the API call 
 */
public void getProductsAsync(
			final double latitude,
			final double longitude,
			final APICallBack<List<Product>> callBack
) {
	//the base uri for api requests
	String _baseUri = Configuration.baseUri;

	//prepare query string for API call
	StringBuilder _queryBuilder = new StringBuilder(_baseUri);
	_queryBuilder.append("/products");

	//process query parameters
	APIHelper.appendUrlWithQueryParameters(_queryBuilder, new HashMap<String, Object>() {
		private static final long serialVersionUID = 4761656829646430014L;
		{
				put( "latitude", latitude );
				put( "longitude", longitude );
		}});
	//validate and preprocess url
	String _queryUrl = APIHelper.cleanUrl(_queryBuilder);

	//load all headers for the outgoing API request
	Map<String, String> _headers = new HashMap<String, String>() {
		private static final long serialVersionUID = 5653732892181137421L;
		{
				put( "user-agent", "APIMATIC 2.0" );
				put( "accept", "application/json" );
				put( "Authorization", String.format("Bearer %1$s", Configuration.oAuthAccessToken) );
		}
	};

	//prepare and invoke the API call request to fetch the response
	final HttpRequest _request = getClientInstance().get(_queryUrl, _headers, null);

	//invoke the callback before request if its not null
	if (getHttpCallBack() != null)
	{
		getHttpCallBack().OnBeforeRequest(_request);
	}

	//invoke request and get response
	Runnable _responseTask = new Runnable() {
		public void run() {
			//make the API call
			getClientInstance().executeAsStringAsync(_request, new APICallBack<HttpResponse>() {
				public void onSuccess(HttpContext _context, HttpResponse _response) {
					try {

						//invoke the callback after response if its not null
						if (getHttpCallBack() != null)	
						{
							getHttpCallBack().OnAfterResponse(_context);
						}

						//Error handling using HTTP status codes
						int _responseCode = _response.getStatusCode();
						if (_responseCode == 500)
							throw new APIException("Unexpected error", _context);

						//handle errors defined at the API level
						validateResponse(_response, _context);

						//extract result from the http response
						String _responseBody = ((HttpStringResponse)_response).getBody();
						List<Product> _result = APIHelper.deserialize(_responseBody,
													new TypeReference<List<Product>>(){});

						//let the caller know of the success
						callBack.onSuccess(_context, _result);
					} catch (APIException error) {
						//let the caller know of the error
						callBack.onFailure(_context, error);
					} catch (IOException ioException) {
						//let the caller know of the caught IO Exception
						callBack.onFailure(_context, ioException);
					} catch (Exception exception) {
						//let the caller know of the caught Exception
						callBack.onFailure(_context, exception);
					}
				}
				public void onFailure(HttpContext _context, Throwable _error) {
					//invoke the callback after response if its not null
					if (getHttpCallBack() != null)	
						{
						getHttpCallBack().OnAfterResponse(_context);
					}

					//let the caller know of the failure
					callBack.onFailure(_context, _error);
				}
			});
		}
	};

	//execute async using thread pool
	APIHelper.getScheduler().execute(_responseTask);
}
                                    
                                    
                            
/**
 * Product Types
 * @param    float64        latitude      parameter: Required
 * @param    float64        longitude     parameter: Required
 * @return	Returns the []*models_pkg.Product response from the API call
 */
func (me *PRODUCTS_IMPL) GetProducts (
            latitude float64,
            longitude float64) ([]*models_pkg.Product, error) {
        //the base uri for api requests
    _queryBuilder := uberapi_lib.BASEURI;

    //prepare query string for API call
   _queryBuilder = _queryBuilder + "/products"

    //variable to hold errors
    var err error = nil
    //process optional query parameters
    _queryBuilder, err = apihelper_pkg.AppendUrlWithQueryParameters(_queryBuilder, map[string]interface{} {
        "latitude" : latitude,
        "longitude" : longitude,
    })
    if err != nil {
        //error in query param handling
        return nil, err
    }

    //validate and preprocess url
    _queryBuilder, err = apihelper_pkg.CleanUrl(_queryBuilder)
    if err != nil {
        //error in url validation or cleaning
        return nil, err
    }

    //prepare headers for the outgoing request
    headers := map[string]interface{} {
        "user-agent" : "APIMATIC 2.0",
        "accept" : "application/json",
    }

    //prepare API request
    _request := unirest.Get(_queryBuilder, headers)
    //and invoke the API call request to fetch the response
    _response, err := unirest.AsString(_request);
    if err != nil {
        //error in API invocation
        return nil, err
    }

    //error handling using HTTP status codes
    if (_response.Code == 500) {
        err = apihelper_pkg.NewAPIError("Unexpected error", _response.Code, _response.RawBody)
    } else if (_response.Code < 200) || (_response.Code > 206) { //[200,206] = HTTP OK
            err = apihelper_pkg.NewAPIError("HTTP Response Not OK", _response.Code, _response.RawBody)
        }
    if(err != nil) {
        //error detected in status code validation
        return nil, err
    }

    //returning the response
    var retVal []*models_pkg.Product
    err = json.Unmarshal(_response.RawBody, &retVal)

    if err != nil {
        //error in parsing
        return nil, err
    }
    return retVal, nil
}
                                    
                                    

/**
 * Product Types
 * @param {double} latitude    Required parameter: Latitude component of location.
 * @param {double} longitude    Required parameter: Longitude component of location.
 * @param {function} callback    Required parameter: Callback function in the form of function(error, response)
 *
 * @return {array}
 */
getProducts : function(latitude, longitude, callback){

	//prepare query string for API call;
	var _baseUri = _configuration.BASEURI;
	
	var _queryBuilder = _baseUri + "/products";
	
	//Process query parameters
	_queryBuilder = _APIHelper.appendUrlWithQueryParameters(_queryBuilder, {
		"latitude" : latitude,
		"longitude" : longitude
	});

	//validate and preprocess url
	var _queryUrl = _APIHelper.cleanUrl(_queryBuilder);
	
	//prepare headers
	var _headers = {
		"accept" : "application/json",
		"Authorization" : "Bearer " + _configuration.oAuthAccessToken
	};

	//Construct the request
	var _options = {
		queryUrl: _queryUrl,
		method: "GET",
		headers: _headers,
	};
	
	//Build the response processing. 
	function cb(_error, _response, _context) {
		if(_error) {
			callback({errorMessage: _error.message, errorCode: _error.code},null,_context);
		} else if (_response.statusCode >= 200 && _response.statusCode <= 206) {
			var parsed = JSON.parse(_response.body);
			parsed = parsed.map(function(model){
				return new Product(model);
			});
			callback(null,parsed,_context);
		} else if (_response.statusCode == 500) {
			callback({errorMessage: "Unexpected error", errorCode: 500, errorResponse:_response.body},null,_context);
		} else {
			callback({errorMessage: "HTTP Response Not OK", errorCode: _response.statusCode, errorResponse:_response.body},null,_context);
		}
	}
	_request(_options, cb);
}
                                    
                                    

Improving API adoption using SDKs

Voxbone is a cloud communications (IaaS) company that enables telephony applications in 50+ countries.

« Automating the generation of SDKs is a very cost-efficient way to provide support for the most popular programming languages, especially since we do not have in-house experts in each of the 10 languages. By promoting the use of our SDKs, we were also able to track users and measure adoption for the newer version of API. »

10%
Version 3

90%
Version 2

60%
Version 3

40%
Version 2

read more

Saving $20,000 in Development costs using APIMATIC

Dude Solutions is a leading SaaS provider for operations management solutions recognized for its world class delivery and innovation.

« In 3 months, across the 7 SDKs that we generate, we've been able to save $20,000 in development costs. Additionally, the cost of maintenance is also eliminated because the effort to update the SDK each time the API changes is absorbed as part of the feature's design cost. Furthermore, development time for SDKs for each language went from 1 week to 18 seconds thanks to APIMATIC. »

read more