A tiny library for parsing and creating urls in a type-safe way
A tiny library for parsing and creating urls in a type-safe way
A tiny library for parsing and creating urls in a type-safe way
A tiny library for parsing and creating urls in a type-safe way
A tiny library for parsing and creating urls in a type-safe way
A tiny library for parsing and creating urls in a type-safe way
Maven plugin to verify a provider ================================= Maven plugin for verifying pacts against a provider. The Maven plugin provides a `verify` goal which will verify all configured pacts against your provider. ## To Use It ### 1. Add the pact-jvm-provider-maven plugin to your `build` section of your pom file. ```xml <build> [...] <plugins> [...] <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> </plugin> [...] </plugins> [...] </build> ``` ### 2. Define the pacts between your consumers and providers You define all the providers and consumers within the configuration element of the maven plugin. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <!-- You can define as many as you need, but each must have a unique name --> <serviceProvider> <name>provider1</name> <!-- All the provider properties are optional, and have sensible defaults (shown below) --> <protocol>http</protocol> <host>localhost</host> <port>8080</port> <path>/</path> <consumers> <!-- Again, you can define as many consumers for each provider as you need, but each must have a unique name --> <consumer> <name>consumer1</name> <!-- currently supports a file path using pactFile or a URL using pactUrl --> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### 3. Execute `mvn pact:verify` You will have to have your provider running for this to pass. ## Verifying all pact files in a directory for a provider You can specify a directory that contains pact files, and the Pact plugin will scan for all pact files that match that provider and define a consumer for each pact file in the directory. Consumer name is read from contents of pact file. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <!-- You can define as many as you need, but each must have a unique name --> <serviceProvider> <name>provider1</name> <!-- All the provider properties are optional, and have sensible defaults (shown below) --> <protocol>http</protocol> <host>localhost</host> <port>8080</port> <path>/</path> <pactFileDirectory>path/to/pacts</pactFileDirectory> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### Verifying all pact files from multiple directories for a provider [3.5.18+] If you want to specify multiple directories, you can use `pactFileDirectories`. The plugin will only fail the build if no pact files are loaded after processing all the directories in the list. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.18</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <pactFileDirectories> <pactFileDirectory>path/to/pacts1</pactFileDirectory> <pactFileDirectory>path/to/pacts2</pactFileDirectory> </pactFileDirectories> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Enabling insecure SSL For providers that are running on SSL with self-signed certificates, you need to enable insecure SSL mode by setting `<insecure>true</insecure>` on the provider. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <pactFileDirectory>path/to/pacts</pactFileDirectory> <insecure>true</insecure> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Specifying a custom trust store For environments that are running their own certificate chains: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <pactFileDirectory>path/to/pacts</pactFileDirectory> <trustStore>relative/path/to/trustStore.jks</trustStore> <trustStorePassword>changeit</trustStorePassword> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` `trustStore` is either relative to the current working (build) directory. `trustStorePassword` defaults to `changeit`. NOTE: The hostname will still be verified against the certificate. ## Modifying the requests before they are sent Sometimes you may need to add things to the requests that can't be persisted in a pact file. Examples of these would be authentication tokens, which have a small life span. The Pact Maven plugin provides a request filter that can be set to a Groovy script on the provider that will be called before the request is made. This script will receive the HttpRequest bound to a variable named `request` prior to it being executed. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <requestFilter> // This is a Groovy script that adds an Authorization header to each request request.addHeader('Authorization', 'oauth-token eyJhbGciOiJSUzI1NiIsIm...') </requestFilter> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` __*Important Note:*__ You should only use this feature for things that can not be persisted in the pact file. By modifying the request, you are potentially modifying the contract from the consumer tests! ## Modifying the HTTP Client Used The default HTTP client is used for all requests to providers (created with a call to `HttpClients.createDefault()`). This can be changed by specifying a closure assigned to createClient on the provider that returns a CloseableHttpClient. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <createClient> // This is a Groovy script that will enable the client to accept self-signed certificates import org.apache.http.ssl.SSLContextBuilder import org.apache.http.conn.ssl.NoopHostnameVerifier import org.apache.http.impl.client.HttpClients HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()) .setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, { x509Certificates, s -> true }) .build()) .build() </createClient> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Turning off URL decoding of the paths in the pact file By default the paths loaded from the pact file will be decoded before the request is sent to the provider. To turn this behaviour off, set the system property `pact.verifier.disableUrlPathDecoding` to `true`. __*Important Note:*__ If you turn off the url path decoding, you need to ensure that the paths in the pact files are correctly encoded. The verifier will not be able to make a request with an invalid encoded path. ## Plugin Properties The following plugin properties can be specified with `-Dproperty=value` on the command line or in the configuration section: |Property|Description| |--------|-----------| |pact.showStacktrace|This turns on stacktrace printing for each request. It can help with diagnosing network errors| |pact.showFullDiff|This turns on displaying the full diff of the expected versus actual bodies| |pact.filter.consumers|Comma separated list of consumer names to verify| |pact.filter.description|Only verify interactions whose description match the provided regular expression| |pact.filter.providerState|Only verify interactions whose provider state match the provided regular expression. An empty string matches interactions that have no state| |pact.verifier.publishResults|Publishing of verification results will be skipped unless this property is set to 'true' [version 3.5.18+]| |pact.matching.wildcard|Enables matching of map values ignoring the keys when this property is set to 'true'| Example in the configuration section: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> <configuration> <pact.showStacktrace>true</pact.showStacktrace> </configuration> </configuration> </plugin> ``` ## Provider States For each provider you can specify a state change URL to use to switch the state of the provider. This URL will receive the providerState description and parameters from the pact file before each interaction via a POST. The stateChangeUsesBody controls if the state is passed in the request body or as query parameters. These values can be set at the provider level, or for a specific consumer. Consumer values take precedent if both are given. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <stateChangeUsesBody>false</stateChangeUsesBody> <!-- defaults to true --> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> <stateChangeUrl>http://localhost:8080/tasks/pactStateChangeForConsumer1</stateChangeUrl> <stateChangeUsesBody>false</stateChangeUsesBody> <!-- defaults to true --> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` If the `stateChangeUsesBody` is not specified, or is set to true, then the provider state description and parameters will be sent as JSON in the body of the request. If it is set to false, they will passed as query parameters. As for normal requests (see Modifying the requests before they are sent), a state change request can be modified before it is sent. Set `stateChangeRequestFilter` to a Groovy script on the provider that will be called before the request is made. #### Teardown calls for state changes You can enable teardown state change calls by setting the property `<stateChangeTeardown>true</stateChangeTeardown>` on the provider. This will add an `action` parameter to the state change call. The setup call before the test will receive `action=setup`, and then a teardown call will be made afterwards to the state change URL with `action=teardown`. ## Verifying pact files from a pact broker You can setup your build to validate against the pacts stored in a pact broker. The pact plugin will query the pact broker for all consumers that have a pact with the provider based on its name. To use it, just configure the `pactBrokerUrl` or `pactBroker` value for the provider with the base URL to the pact broker. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBrokerUrl>http://pact-broker:5000/</pactBrokerUrl> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### Verifying pacts from an authenticated pact broker If your pact broker requires authentication (basic authentication is only supported), you can configure the username and password to use by configuring the `authentication` element of the `pactBroker` element of your provider. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBroker> <url>http://pactbroker:1234</url> <authentication> <username>test</username> <password>test</password> </authentication> </pactBroker> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` #### Using the Maven servers configuration [version 3.5.6+] From version 3.5.6, you can use the servers setup in the Maven settings. To do this, setup a server as per the [Maven Server Settings](https://maven.apache.org/settings.html#Servers). Then set the server ID in the pact broker configuration in your POM. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.6</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBroker> <url>http://pactbroker:1234</url> <serverId>test-pact-broker</serverId> <!-- This must match the server id in the maven settings --> </pactBroker> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### Verifying pacts from an pact broker that match particular tags If your pacts in your pact broker have been tagged, you can set the tags to fetch by configuring the `tags` element of the `pactBroker` element of your provider. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBroker> <url>http://pactbroker:1234</url> <tags> <tag>TEST</tag> <tag>DEV</tag> </tags> </pactBroker> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` This example will fetch and validate the pacts for the TEST and DEV tags. ## Filtering the interactions that are verified You can filter the interactions that are run using three properties: `pact.filter.consumers`, `pact.filter.description` and `pact.filter.providerState`. Adding `-Dpact.filter.consumers=consumer1,consumer2` to the command line or configuration section will only run the pact files for those consumers (consumer1 and consumer2). Adding `-Dpact.filter.description=a request for payment.*` will only run those interactions whose descriptions start with 'a request for payment'. `-Dpact.filter.providerState=.*payment` will match any interaction that has a provider state that ends with payment, and `-Dpact.filter.providerState=` will match any interaction that does not have a provider state. ## Not failing the build if no pact files are found [version 3.5.19+] By default, if there are no pact files to verify, the plugin will raise an exception. This is to guard against false positives where the build is passing but nothing has been verified due to mis-configuration. To disable this behaviour, set the `failIfNoPactsFound` parameter to `false`. # Verifying a message provider The Maven plugin has been updated to allow invoking test methods that can return the message contents from a message producer. To use it, set the way to invoke the verification to `ANNOTATED_METHOD`. This will allow the pact verification task to scan for test methods that return the message contents. Add something like the following to your maven pom file: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>messageProvider</name> <verificationType>ANNOTATED_METHOD</verificationType> <!-- packagesToScan is optional, but leaving it out will result in the entire test classpath being scanned. Set it to the packages where your annotated test method can be found. --> <packagesToScan> <packageToScan>au.com.example.messageprovider.*</packageToScan> </packagesToScan> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/messageprovider-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` Now when the pact verify task is run, will look for methods annotated with `@PactVerifyProvider` in the test classpath that have a matching description to what is in the pact file. ```groovy class ConfirmationKafkaMessageBuilderTest { @PactVerifyProvider('an order confirmation message') String verifyMessageForOrder() { Order order = new Order() order.setId(10000004) order.setExchange('ASX') order.setSecurityCode('CBA') order.setPrice(BigDecimal.TEN) order.setUnits(15) order.setGst(new BigDecimal('15.0')) odrer.setFees(BigDecimal.TEN) def message = new ConfirmationKafkaMessageBuilder() .withOrder(order) .build() JsonOutput.toJson(message) } } ``` It will then validate that the returned contents matches the contents for the message in the pact file. ## Changing the class path that is scanned By default, the test classpath is scanned for annotated methods. You can override this by setting the `classpathElements` property: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <serviceProviders> <serviceProvider> <name>messageProvider</name> <verificationType>ANNOTATED_METHOD</verificationType> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/messageprovider-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> <classpathElements> <classpathElement> build/classes/test </classpathElement> </classpathElements> </configuration> </plugin> ``` # Publishing pact files to a pact broker The pact maven plugin provides a `publish` mojo that can publish all pact files in a directory to a pact broker. To use it, you need to add a publish configuration to the POM that defines the directory where the pact files are and the URL to the pact broker. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <pactDirectory>path/to/pact/files</pactDirectory> <!-- Defaults to ${project.build.directory}/pacts --> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <projectVersion>1.0.100</projectVersion> <!-- Defaults to ${project.version} --> <trimSnapshot>true</trimSnapshot> <!-- Defaults to false --> </configuration> </plugin> ``` You can now execute `mvn pact:publish` to publish the pact files. _NOTE:_ The pact broker requires a version for all published pacts. The `publish` task will use the version of the project by default, but can be overwritten with the `projectVersion` property. Make sure you have set one otherwise the broker will reject the pact files. _NOTE_: By default, the pact broker has issues parsing `SNAPSHOT` versions. You can configure the publisher to automatically remove `-SNAPSHOT` from your version number by setting `trimSnapshot` to true. This setting does not modify non-snapshot versions. You can set any tags that the pacts should be published with by setting the `tags` list property (version 3.5.12+). A common use of this is setting the tag to the current source control branch. This supports using pact with feature branches. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.12</version> <configuration> <pactDirectory>path/to/pact/files</pactDirectory> <!-- Defaults to ${project.build.directory}/pacts --> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <projectVersion>1.0.100</projectVersion> <!-- Defaults to ${project.version} --> <tags> <tag>feature/feature_name</tag> </tags> </configuration> </plugin> ``` ## Publishing to an authenticated pact broker For an authenticated pact broker, you can pass in the credentials with the `pactBrokerUsername` and `pactBrokerPassword` properties. Currently it only supports basic authentication. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.11</version> <configuration> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <pactBrokerUsername>USERNAME</pactBrokerUsername> <pactBrokerPassword>PASSWORD</pactBrokerPassword> </configuration> </plugin> ``` #### Using the Maven servers configuration [version 3.5.6+] From version 3.5.6, you can use the servers setup in the Maven settings. To do this, setup a server as per the [Maven Server Settings](https://maven.apache.org/settings.html#Servers). Then set the server ID in the pact broker configuration in your POM. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.5.19</version> <configuration> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <pactBrokerServerId>test-pact-broker</pactBrokerServerId> <!-- This must match the server id in the maven settings --> </configuration> </plugin> ``` ## Excluding pacts from being published [version 3.5.19+] You can exclude some of the pact files from being published by providing a list of regular expressions that match against the base names of the pact files. For example: ```groovy pact { publish { pactBrokerUrl = 'https://mypactbroker.com' excludes = [ '.*\\-\\d+$' ] // exclude all pact files that end with a dash followed by a number in the name } } ``` ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.19</version> <configuration> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <excludes> <exclude>.*\\-\\d+$</exclude> <!-- exclude pact files where the name ends in a dash followed by a number --> </excludes> </configuration> </plugin> ``` # Publishing verification results to a Pact Broker [version 3.5.4+] For pacts that are loaded from a Pact Broker, the results of running the verification can be published back to the broker against the URL for the pact. You will be able to then see the result on the Pact Broker home screen. To turn on the verification publishing, set the system property `pact.verifier.publishResults` to `true` in the pact maven plugin, not surefire, configuration. # Enabling other verification reports [version 3.5.20+] By default the verification report is written to the console. You can also enable a JSON or Markdown report by setting the `reports` configuration list. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.12</artifactId> <version>3.5.20</version> <configuration> <reports> <report>console</report> <report>json</report> <report>markdown</report> </reports> </configuration> </plugin> ``` These reports will be written to `target/reports/pact`.
Parses data: URLs
jsoup is a Java library for working with real-world HTML. It provides a very convenient API for fetching URLs and extracting and manipulating data, using the best of HTML5 DOM methods and CSS selectors. jsoup implements the WHATWG HTML5 specification, and parses HTML to the same DOM as modern browsers do.
Helper library for parsing Database URL into JDBC connection
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
If you are using Postman, you can: - Use the **Download** button above to download the m3ter Open API spec JSON file and then import this file as the **m3ter API Collection** into your Workspace. See [Importing the m3ter Open API](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls#importing-the-m3ter-open-api) in our main user Documentation for details. - Copy this link: [m3ter-Template API Collection](https://www.datocms-assets.com/78893/1672846767-m3ter-template-api-collection-postman_collection.json) and use it to import the **m3ter-Template API Collection** into your Workspace. See [Importing the m3ter Template API Collection](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls#importing-the-m3ter-template-api-collection) in our main user Documentation for details. --- # Introduction The m3ter platform supports two HTTP-based REST APIs returning JSON encoded responses: - The **Ingest API**, which you can use for submitting raw data measurements. _(See the [Submit Measurements](https://www.m3ter.com/docs/api#tag/Measurements/operation/SubmitMeasurements) endpoint in these API Reference Docs.)_ - The **Config API**, which you can use for configuration and management. _(All other endpoints in these API Reference Docs.)_ ## Authentication and Authorization Our APIs use an industry-standard authorization protocol known as the OAuth 2.0 specification. OAuth2 supports several grant types, each designed for a specific use case. m3ter uses the following two grant types: - **Authorization Code**: Used for human login access via the m3ter Console. - **Client Credentials**: Used for machine-to-machine communication and API access. Complete the following flow for API access: 1. **Create a Service User and add Permissions**: Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. 2. **Generate Access Keys**: In the Console, open the _Overview_ page for the Service User by clicking on the name. Generate an **Access Key id** and **Api Secret**. Make sure you copy the **Api Secret** because it is only visible at the time of creation. See [Service Authentication](https://www.m3ter.com/docs/guides/authenticating-with-the-platform/service-authentication) for detailed instructions and an example. 3. **Obtain a Bearer Token using Basic Auth**: We implement the OAuth 2.0 Client Credentials Grant authentication flow for Service User Authentication. Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. _See examples below._ 4. **Bearer Token Usage**: Use the HTTP 'Authorization' header with the bearer token to authorise all subsequent API requests. > Warning: The Bearer Token is valid for 18,000 seconds or 5 hours. When the > token has expired, you must obtain a new bearer token. Below are two examples for obtaining a Bearer Token using Basic Auth: the first in cURL and the second as a Python script. ### cURL Example 1. Open your terminal or command prompt. 2. Use the following `cURL` command to obtain a Bearer Token: ```bash curl -X POST https://api.m3ter.com/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -u your_access_key_id:your_api_secret \ -d 'grant_type=client_credentials' ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. 3. Run the command, and if successful, it will return a JSON response containing the Bearer Token. The response will look like this: ```json { "access_token": "your_bearer_token", "token_type": "Bearer", "expires_in": 18000 } ``` You can then use the Bearer Token _(the value of `"access_token"`)_ for subsequent API calls to m3ter. ### Python Example 1. Install the `requests` library if you haven't already: ```bash pip install requests ``` 2. Use the following Python script to obtain a Bearer Token: ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. 3. Run the script, and if successful, it will print the Bearer Token. You can then use this Bearer Token for subsequent API calls to m3ter. ## Submitting Personally Identifiable Information (PII) **IMPORTANT!** Under the [Data Processing Agreement](https://www.m3ter.com/docs/legal/dpa), the only fields permissible for use to submit any of your end-customer PII data in m3ter are the `name`, `address`, and `emailAddress` fields on the **Account** entity - see the details for [Create Account](https://www.m3ter.com/docs/api#operation/PostAccount). See also section 4.2 of the [Terms of Service](https://www.m3ter.com/docs/legal/terms-of-service). ## Error Codes The APIs return standard HTTP response codes to indicate request success or failure. - `200` code indicates success. - `4xx` codes are failures due to problems with the request _(client side errors)_. - `5xx` codes indicate valid API requests and the failure is on the server side. See [HTTP Error Codes](https://www.m3ter.com/docs/guides/m3ter-apis/http-error-codes) for examples and more information. ## Rate and Payload Limits ### Config API Request Rate Limits - **Source IP Address.** Individual host machines can send up to 20,000 requests over a rolling 5-minute period. _(An average of 66 requests per second)._ - **m3ter Organization** Each m3ter Organization can send a maximum of 50 requests per second from any number of source IP addresses. If you exceed either of these rate limits, requests are throttled and an HTTP 429 _(Too Many Requests)_ error response is returned: - **Source IP address rate limit** - 429 is returned until the total number of requests in the rolling 5-minute period drops below 20,000. - **m3ter Organization rate limit** - 429 is returned for the remainder of the second in which throttling has occurred. See [Config API Limits](https://www.m3ter.com/docs/guides/m3ter-apis/config-api-limits) for more information. ### Data Explorer API Request Rate Limits As part of the Config API, requests made to the Data Explorer are subject to tighter request rate limits: - **Generally** 1 request per second. - **Burst** 10 requests per second. If you exceed either of these rate limits, requests are throttled and an HTTP 429 (Too Many Requests) error response is returned. **Note: Burst limit for Data Explorer requests?** We allow short bursts of higher TPS to allow us to accommodate occasional spikes. For example, if the sustained rate is 50 TPS, we might set a bucket capacity (N) of 150. This means that you can do up to 150 TPS for 1s (and empty the bucket), but in the next second you'll only be able to do 50 TPS because that is all that has been refilled. If requests drop below 50 TPS for a period of time, the bucket will refill back up to full capacity allowing another spike. This is usually referred to as "burst capacity". ### Ingest API Request Rate and Payload Limits #### Request Rate Limits - **Source IP Address.** Individual host machines can send up to 5,000 requests over a rolling 5-minute period. _(An average of 16 requests per second)_. - **m3ter Organization.** Each m3ter Organization can send a maximum of 50 requests per second from any number of source IP addresses. If you exceed either of these rate limits, requests are throttled and an HTTP 429 _(Too Many Requests)_ error response is returned: - **Source IP address rate limit** - 429 is returned until the total number of requests in the rolling 5-minute period drops below 5,000. - **m3ter Organization rate limit** - 429 is returned for the remainder of the second in which throttling has occurred. #### Payload Limit For the Ingest API, the maximum request payload size allowed is 512KB. If you exceed this request payload limit, then you'll receive a 403 (Forbidden) error response. See [Ingest API Limits](https://www.m3ter.com/docs/guides/m3ter-apis/ingest-api-limits) for more information. ## Pagination **List Endpoints** API endpoints that have a List resources request support cursor-based pagination - for example, the `List Accounts` request. These List calls support pagination by taking the two parameters `pageSize` and `nextToken`. The response of a List API call is a single page list. If the `nextToken` parameter is not supplied, the first page returned contains the newest objects chronologically. Specify a `nextToken` to retrieve the page of older objects that occur immediately after the last object on the previous page. Use `pageSize` to limit the list results per page, typically this allows up to a maximum of 100 or 200 per page. **Search Endpoints** API endpoints that have a Search resources request support cursor-based pagination - for example, the `Search Accounts` request. These Search calls support pagination by taking the two parameters `pageSize` and `fromDocument`. The response of a Search API call is a single page list. If the `fromDocument` parameter is not supplied, the first page returned contains the newest objects chronologically. Specify a `fromDocument` to retrieve the page of older objects that occur immediately after the last object on the previous page. Use `pageSize` to limit the list results per page, typically this allows up to a maximum of 100 or 200 per page. Default is 10. ## Changelog Check out the latest API features, updates, and functionality by looking in the API Updates subsection of the [m3ter Changelog](https://www.m3ter.com/docs/changelog). --- API Quick Start This API Quick Start section provides an entry point to using the m3ter APIs. The example given takes you through the steps of first authenticating with the m3ter platform then going on to retrieve a list of Accounts for your Organization. Code examples are provided in Python, JavaScript, C++, and command line HTTP via `cURL`. See also [Getting Started with API Calls](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls) for more on using our API with examples. ## Step 1: Create a Service User and add Permissions Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. ## Step 2: Generate Access Keys In the Console, open the **Service Users Details** page for the Service User by clicking on the Service User **NAME**. Generate an **Access Key id** and **Api Secret**. Make sure to copy the **Api Secret** as it is only visible at the time of creation. For further guidance on these two steps, see [Creating and Configuring Service Users](https://www.m3ter.com/docs/guides/organization-and-access-management/managing-users/creating-and-configuring-service-users) in our main user Documentation. ## Step 3: Install Dependencies (if applicable) ### Python Install the `requests` library: ```bash pip install requests ``` ### JavaScript Install the `axios` library: ```bash npm install axios ``` ### C++ Install the `libcurl` and `jsoncpp` libraries. For Windows based systems with `vcpkg` package manager installed: ```bash vcpkg install curl[openssl] jsoncpp ``` For Debian based Linux operating systems: ```bash sudo apt-get install libcurl4-openssl-dev libjsoncpp-dev ``` ## Step 4: Obtain a Bearer Token using Basic Auth Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. ### cURL ```bash curl -X POST https://api.m3ter.com/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -u your_access_key_id:your_api_secret \ -d 'grant_type=client_credentials' ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the command, and if successful, it will return a JSON response containing the Bearer Token. ### Python ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ### JavaScript ```javascript const axios = require("axios"); const btoa = require("btoa"); const accessKeyId = "your_access_key_id"; const apiSecret = "your_api_secret"; const basicAuth = btoa(`${accessKeyId}:${apiSecret}`); const url = "https://api.m3ter.com/oauth/token"; const options = { method: "POST", url: url, headers: { Authorization: `Basic ${basicAuth}`, "Content-Type": "application/json", }, data: { grant_type: "client_credentials", }, }; axios(options) .then((response) => console.log("Access Token:", response.data.access_token)) .catch((error) => console.error("Error:", error)); ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ### C++ ```C++ #include <iostream> #include <string> #include <curl/curl.h> #include <json/json.h> #include <sstream> #include <cstdlib> #include <base64.h> size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string *)userp)->append((char *)contents, size * nmemb); return size * nmemb; } int main() { // Replace these with your Access Key id and Api Secret std::string access_key_id = "your_access_key_id"; std::string api_secret = "your_api_secret"; // Encode the Access Key id and Api Secret in base64 format std::string credentials = base64_encode(reinterpret_cast<const unsigned char*>(access_key_id.append(":").append(api_secret).c_str()), access_key_id.length()); // Set the m3ter token endpoint URL std::string token_url = "https://api.m3ter.com/oauth/token"; // Initialize libcurl curl_global_init(CURL_GLOBAL_DEFAULT); CURL *curl = curl_easy_init(); if (curl) { // Set the headers for the request struct curl_slist *headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); std::string auth_header = "Authorization: Basic " + credentials; headers = curl_slist_append(headers, auth_header.c_str()); // Set the payload for the request std::string payload = "grant_type=client_credentials"; // Prepare the request curl_easy_setopt(curl, CURLOPT_URL, token_url.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); // Send the request and store the response std::string response; curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); // Check if the request was successful if (res != CURLE_OK || response_code != 200) { std::cerr << "Error: " << response_code << " - " << curl_easy_strerror(res) << std::endl; } else { // Parse the JSON response Json::Value json; std::istringstream(response) >> json; std::string bearer_token = json["access_token"].asString(); std::cout << "Bearer Token: " << bearer_token << std::endl; } // Cleanup curl_easy_cleanup(curl); curl_slist_free_all(headers); } curl_global_cleanup(); return 0; } ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the program, and if successful, it will print the Bearer Token. ## Step 5: Retrieve Organization ID Copy your Organization ID from the m3ter Console by going to **Settings**, **Organization**, then the **Configuration** tab. The Organization ID is displayed on the _Organization Details_ card and you can **Copy** it directly to your clipboard. ## Step 6: Retrieve Accounts List Make a call to the [List Accounts](https://www.m3ter.com/docs/api#tag/Account/operation/ListAccounts) API endpoint using the Organization ID copied in the previous step. Use the Bearer Token to authorize API calls in the HTTP 'Authorization' header. ### cURL ```bash curl -X GET "https://api.m3ter.com/organizations/{orgId}/accounts?pageSize={pageSize}&nextToken={nextToken}" \ -H "Authorization: Bearer {access_token}" ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### Python ```python import requests org_id = 'your_org_id' page_size = 'your_page_size' next_token = 'your_next_token' # Optional, use if needed access_token = 'your_bearer_token' url = f'https://api.m3ter.com/organizations/{org_id}/accounts?pageSize={page_size}&nextToken={next_token}' headers = { 'Authorization': f'Bearer {access_token}' } response = requests.get(url, headers=headers) if response.status_code == 200: accounts = response.json() print(accounts) else: print(f"Error: {response.status_code}") ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### JavaScript ```javascript const axios = require("axios"); const org_id = "your_org_id"; const page_size = "your_page_size"; const next_token = "your_next_token"; // Optional, use if needed const access_token = "your_bearer_token"; const url = `https://api.m3ter.com/organizations/${org_id}/accounts?pageSize=${page_size}&nextToken=${next_token}`; const headers = { Authorization: `Bearer ${access_token}`, }; axios .get(url, { headers }) .then((response) => { if (response.status === 200) { const accounts = response.data; console.log(accounts); } else { console.log(`Error: ${response.status}`); } }) .catch((error) => { console.error(`Error: ${error.response.status}`); }); ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### C++ ```C++ #include <iostream> #include <string> #include <sstream> #include <curl/curl.h> #include <json/json.h> size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } int main() { std::string org_id = "your_org_id"; std::string page_size = "your_page_size"; std::string next_token = "your_next_token"; // Optional, use if needed std::string access_token = "your_bearer_token"; std::string url = "https://api.m3ter.com/organizations/" + org_id + "/accounts?pageSize=" + page_size + "&nextToken=" + next_token; std::string auth_header = "Authorization: Bearer " + access_token; std::string read_buffer; CURL* curl = curl_easy_init(); if(curl) { struct curl_slist* headers = NULL; headers = curl_slist_append(headers, auth_header.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); if (response_code == 200) { Json::Value jsonData; Json::CharReaderBuilder jsonReader; std::string errs; std::istringstream iss(read_buffer); if (Json::parseFromStream(jsonReader, iss, &jsonData, &errs)) { std::cout << jsonData << std::endl; } } else { std::cout << "Error: " << response_code << std::endl; } } curl_easy_cleanup(curl); curl_slist_free_all(headers); } return 0; } ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. --- # Integrations Webhook API Example A major benefit of using m3ter is that it seamlessly integrates with your current technology stack. You can create webhook destinations to link you integrations using the API, or via the Console: - This section provides a worked example showing you how to set up a Webhook via the API. - See [Creating and Managing Destinations](https://www.m3ter.com/docs/guides/integrations/setting-up-native-integrations/creating-and-managing-destinations) in the m3ter documentation for instructions on using the Console. ## Step 1: Create a Service User and Generate Access Keys 1. **Create a Service User**: Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. 2. **Generate Access Keys**: In the Console, open the **Service User Details** page for the Service User by clicking on the **NAME** hotlink text. Select **Generate Access Key** to generate an **Access Key id** and **Api Secret**. Make sure you copy the **Api Secret** because it is only visible at the time of creation. For further guidance on completing **Step 1**, see [Creating and Configuring Service Users](https://www.m3ter.com/docs/guides/organization-and-access-management/managing-users/creating-and-configuring-service-users) in our main user Documentation. ## Step 2: Obtain a Bearer Token using Basic Auth We implement the OAuth 2.0 Client Credentials Grant authentication flow for Service User Authentication. Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. Here's an example in Python code: ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ## Step 3: Create a Webhook (Destination) After obtaining the Bearer Token, you can use it to authorize your API calls. Here's a Python example of creating a webhook: ```python import requests import json # API endpoint url = "https://api.m3ter.com/organizations/{orgId}/integrationdestinations/webhooks" # replace {orgId} with your organization's UUID # Headers headers = { "Content-Type": "application/json", "Authorization": f"Bearer {bearer_token}" # replace with your actual Bearer Token } # Request body payload = { "url": "https://your-webhook-listener.com", # replace with your actual webhook listener URL "credentials": { "type": "M3TER_SIGNED_REQUEST", "apiKey": access_key_id, # replace with your actual API key "secret": api_secret # replace with your actual secret } } # Make the POST request response = requests.post(url, headers=headers, data=json.dumps(payload)) # Print the response print(response.json()) ``` ## Step 4: Validate Incoming Requests Once your webhook is set up, you'll want to validate incoming requests to ensure they're coming from m3ter. All requests we make to your webhook are signed by us. When you receive a request on your configured endpoint, validate the `X-m3ter-signature` header by preparing a payload string that you sign with your API secret. You must concatenate the following data using a pipe '|' separator to compute the payload: - url - query string - Currently, there's no support for passing in query parameters. For now, you can hard code to this string: '{}' - API Key - provided in the `X-m3ter-apikey` header. - timestamp - provided in the `X-m3ter-timestamp` header. - body - the request body. You can now set up and validate webhooks using the m3ter Console and API. Always refer to the latest [m3ter documentation](https://www.m3ter.com/docs) for accurate and up to date information. --- # Authentication <!-- ReDoc-Inject: <security-definitions> -->
If you are using Postman, you can: - Use the **Download** button above to download the m3ter Open API spec JSON file and then import this file as the **m3ter API Collection** into your Workspace. See [Importing the m3ter Open API](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls#importing-the-m3ter-open-api) in our main user Documentation for details. - Copy this link: [m3ter-Template API Collection](https://www.datocms-assets.com/78893/1672846767-m3ter-template-api-collection-postman_collection.json) and use it to import the **m3ter-Template API Collection** into your Workspace. See [Importing the m3ter Template API Collection](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls#importing-the-m3ter-template-api-collection) in our main user Documentation for details. --- # Introduction The m3ter platform supports two HTTP-based REST APIs returning JSON encoded responses: - The **Ingest API**, which you can use for submitting raw data measurements. _(See the [Submit Measurements](https://www.m3ter.com/docs/api#tag/Measurements/operation/SubmitMeasurements) endpoint in these API Reference Docs.)_ - The **Config API**, which you can use for configuration and management. _(All other endpoints in these API Reference Docs.)_ ## Authentication and Authorization Our APIs use an industry-standard authorization protocol known as the OAuth 2.0 specification. OAuth2 supports several grant types, each designed for a specific use case. m3ter uses the following two grant types: - **Authorization Code**: Used for human login access via the m3ter Console. - **Client Credentials**: Used for machine-to-machine communication and API access. Complete the following flow for API access: 1. **Create a Service User and add Permissions**: Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. 2. **Generate Access Keys**: In the Console, open the _Overview_ page for the Service User by clicking on the name. Generate an **Access Key id** and **Api Secret**. Make sure you copy the **Api Secret** because it is only visible at the time of creation. See [Service Authentication](https://www.m3ter.com/docs/guides/authenticating-with-the-platform/service-authentication) for detailed instructions and an example. 3. **Obtain a Bearer Token using Basic Auth**: We implement the OAuth 2.0 Client Credentials Grant authentication flow for Service User Authentication. Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. _See examples below._ 4. **Bearer Token Usage**: Use the HTTP 'Authorization' header with the bearer token to authorise all subsequent API requests. > Warning: The Bearer Token is valid for 18,000 seconds or 5 hours. When the > token has expired, you must obtain a new bearer token. Below are two examples for obtaining a Bearer Token using Basic Auth: the first in cURL and the second as a Python script. ### cURL Example 1. Open your terminal or command prompt. 2. Use the following `cURL` command to obtain a Bearer Token: ```bash curl -X POST https://api.m3ter.com/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -u your_access_key_id:your_api_secret \ -d 'grant_type=client_credentials' ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. 3. Run the command, and if successful, it will return a JSON response containing the Bearer Token. The response will look like this: ```json { "access_token": "your_bearer_token", "token_type": "Bearer", "expires_in": 18000 } ``` You can then use the Bearer Token _(the value of `"access_token"`)_ for subsequent API calls to m3ter. ### Python Example 1. Install the `requests` library if you haven't already: ```bash pip install requests ``` 2. Use the following Python script to obtain a Bearer Token: ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. 3. Run the script, and if successful, it will print the Bearer Token. You can then use this Bearer Token for subsequent API calls to m3ter. ## Submitting Personally Identifiable Information (PII) **IMPORTANT!** Under the [Data Processing Agreement](https://www.m3ter.com/docs/legal/dpa), the only fields permissible for use to submit any of your end-customer PII data in m3ter are the `name`, `address`, and `emailAddress` fields on the **Account** entity - see the details for [Create Account](https://www.m3ter.com/docs/api#operation/PostAccount). See also section 4.2 of the [Terms of Service](https://www.m3ter.com/docs/legal/terms-of-service). ## Error Codes The APIs return standard HTTP response codes to indicate request success or failure. - `200` code indicates success. - `4xx` codes are failures due to problems with the request _(client side errors)_. - `5xx` codes indicate valid API requests and the failure is on the server side. See [HTTP Error Codes](https://www.m3ter.com/docs/guides/m3ter-apis/http-error-codes) for examples and more information. ## Rate and Payload Limits ### Config API Request Rate Limits - **Source IP Address.** Individual host machines can send up to 20,000 requests over a rolling 5-minute period. _(An average of 66 requests per second)._ - **m3ter Organization** Each m3ter Organization can send a maximum of 50 requests per second from any number of source IP addresses. If you exceed either of these rate limits, requests are throttled and an HTTP 429 _(Too Many Requests)_ error response is returned: - **Source IP address rate limit** - 429 is returned until the total number of requests in the rolling 5-minute period drops below 20,000. - **m3ter Organization rate limit** - 429 is returned for the remainder of the second in which throttling has occurred. See [Config API Limits](https://www.m3ter.com/docs/guides/m3ter-apis/config-api-limits) for more information. ### Data Explorer API Request Rate Limits As part of the Config API, requests made to the Data Explorer are subject to tighter request rate limits: - **Generally** 1 request per second. - **Burst** 10 requests per second. If you exceed either of these rate limits, requests are throttled and an HTTP 429 (Too Many Requests) error response is returned. **Note: Burst limit for Data Explorer requests?** We allow short bursts of higher TPS to allow us to accommodate occasional spikes. For example, if the sustained rate is 50 TPS, we might set a bucket capacity (N) of 150. This means that you can do up to 150 TPS for 1s (and empty the bucket), but in the next second you'll only be able to do 50 TPS because that is all that has been refilled. If requests drop below 50 TPS for a period of time, the bucket will refill back up to full capacity allowing another spike. This is usually referred to as "burst capacity". ### Ingest API Request Rate and Payload Limits #### Request Rate Limits - **Source IP Address.** Individual host machines can send up to 5,000 requests over a rolling 5-minute period. _(An average of 16 requests per second)_. - **m3ter Organization.** Each m3ter Organization can send a maximum of 50 requests per second from any number of source IP addresses. If you exceed either of these rate limits, requests are throttled and an HTTP 429 _(Too Many Requests)_ error response is returned: - **Source IP address rate limit** - 429 is returned until the total number of requests in the rolling 5-minute period drops below 5,000. - **m3ter Organization rate limit** - 429 is returned for the remainder of the second in which throttling has occurred. #### Payload Limit For the Ingest API, the maximum request payload size allowed is 512KB. If you exceed this request payload limit, then you'll receive a 403 (Forbidden) error response. See [Ingest API Limits](https://www.m3ter.com/docs/guides/m3ter-apis/ingest-api-limits) for more information. ## Pagination **List Endpoints** API endpoints that have a List resources request support cursor-based pagination - for example, the `List Accounts` request. These List calls support pagination by taking the two parameters `pageSize` and `nextToken`. The response of a List API call is a single page list. If the `nextToken` parameter is not supplied, the first page returned contains the newest objects chronologically. Specify a `nextToken` to retrieve the page of older objects that occur immediately after the last object on the previous page. Use `pageSize` to limit the list results per page, typically this allows up to a maximum of 100 or 200 per page. **Search Endpoints** API endpoints that have a Search resources request support cursor-based pagination - for example, the `Search Accounts` request. These Search calls support pagination by taking the two parameters `pageSize` and `fromDocument`. The response of a Search API call is a single page list. If the `fromDocument` parameter is not supplied, the first page returned contains the newest objects chronologically. Specify a `fromDocument` to retrieve the page of older objects that occur immediately after the last object on the previous page. Use `pageSize` to limit the list results per page, typically this allows up to a maximum of 100 or 200 per page. Default is 10. ## Changelog Check out the latest API features, updates, and functionality by looking in the API Updates subsection of the [m3ter Changelog](https://www.m3ter.com/docs/changelog). --- API Quick Start This API Quick Start section provides an entry point to using the m3ter APIs. The example given takes you through the steps of first authenticating with the m3ter platform then going on to retrieve a list of Accounts for your Organization. Code examples are provided in Python, JavaScript, C++, and command line HTTP via `cURL`. See also [Getting Started with API Calls](https://www.m3ter.com/docs/guides/m3ter-apis/getting-started-with-api-calls) for more on using our API with examples. ## Step 1: Create a Service User and add Permissions Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. ## Step 2: Generate Access Keys In the Console, open the **Service Users Details** page for the Service User by clicking on the Service User **NAME**. Generate an **Access Key id** and **Api Secret**. Make sure to copy the **Api Secret** as it is only visible at the time of creation. For further guidance on these two steps, see [Creating and Configuring Service Users](https://www.m3ter.com/docs/guides/organization-and-access-management/managing-users/creating-and-configuring-service-users) in our main user Documentation. ## Step 3: Install Dependencies (if applicable) ### Python Install the `requests` library: ```bash pip install requests ``` ### JavaScript Install the `axios` library: ```bash npm install axios ``` ### C++ Install the `libcurl` and `jsoncpp` libraries. For Windows based systems with `vcpkg` package manager installed: ```bash vcpkg install curl[openssl] jsoncpp ``` For Debian based Linux operating systems: ```bash sudo apt-get install libcurl4-openssl-dev libjsoncpp-dev ``` ## Step 4: Obtain a Bearer Token using Basic Auth Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. ### cURL ```bash curl -X POST https://api.m3ter.com/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -u your_access_key_id:your_api_secret \ -d 'grant_type=client_credentials' ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the command, and if successful, it will return a JSON response containing the Bearer Token. ### Python ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ### JavaScript ```javascript const axios = require("axios"); const btoa = require("btoa"); const accessKeyId = "your_access_key_id"; const apiSecret = "your_api_secret"; const basicAuth = btoa(`${accessKeyId}:${apiSecret}`); const url = "https://api.m3ter.com/oauth/token"; const options = { method: "POST", url: url, headers: { Authorization: `Basic ${basicAuth}`, "Content-Type": "application/json", }, data: { grant_type: "client_credentials", }, }; axios(options) .then((response) => console.log("Access Token:", response.data.access_token)) .catch((error) => console.error("Error:", error)); ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ### C++ ```C++ #include <iostream> #include <string> #include <curl/curl.h> #include <json/json.h> #include <sstream> #include <cstdlib> #include <base64.h> size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string *)userp)->append((char *)contents, size * nmemb); return size * nmemb; } int main() { // Replace these with your Access Key id and Api Secret std::string access_key_id = "your_access_key_id"; std::string api_secret = "your_api_secret"; // Encode the Access Key id and Api Secret in base64 format std::string credentials = base64_encode(reinterpret_cast<const unsigned char*>(access_key_id.append(":").append(api_secret).c_str()), access_key_id.length()); // Set the m3ter token endpoint URL std::string token_url = "https://api.m3ter.com/oauth/token"; // Initialize libcurl curl_global_init(CURL_GLOBAL_DEFAULT); CURL *curl = curl_easy_init(); if (curl) { // Set the headers for the request struct curl_slist *headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); std::string auth_header = "Authorization: Basic " + credentials; headers = curl_slist_append(headers, auth_header.c_str()); // Set the payload for the request std::string payload = "grant_type=client_credentials"; // Prepare the request curl_easy_setopt(curl, CURLOPT_URL, token_url.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); // Send the request and store the response std::string response; curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); // Check if the request was successful if (res != CURLE_OK || response_code != 200) { std::cerr << "Error: " << response_code << " - " << curl_easy_strerror(res) << std::endl; } else { // Parse the JSON response Json::Value json; std::istringstream(response) >> json; std::string bearer_token = json["access_token"].asString(); std::cout << "Bearer Token: " << bearer_token << std::endl; } // Cleanup curl_easy_cleanup(curl); curl_slist_free_all(headers); } curl_global_cleanup(); return 0; } ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the program, and if successful, it will print the Bearer Token. ## Step 5: Retrieve Organization ID Copy your Organization ID from the m3ter Console by going to **Settings**, **Organization**, then the **Configuration** tab. The Organization ID is displayed on the _Organization Details_ card and you can **Copy** it directly to your clipboard. ## Step 6: Retrieve Accounts List Make a call to the [List Accounts](https://www.m3ter.com/docs/api#tag/Account/operation/ListAccounts) API endpoint using the Organization ID copied in the previous step. Use the Bearer Token to authorize API calls in the HTTP 'Authorization' header. ### cURL ```bash curl -X GET "https://api.m3ter.com/organizations/{orgId}/accounts?pageSize={pageSize}&nextToken={nextToken}" \ -H "Authorization: Bearer {access_token}" ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### Python ```python import requests org_id = 'your_org_id' page_size = 'your_page_size' next_token = 'your_next_token' # Optional, use if needed access_token = 'your_bearer_token' url = f'https://api.m3ter.com/organizations/{org_id}/accounts?pageSize={page_size}&nextToken={next_token}' headers = { 'Authorization': f'Bearer {access_token}' } response = requests.get(url, headers=headers) if response.status_code == 200: accounts = response.json() print(accounts) else: print(f"Error: {response.status_code}") ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### JavaScript ```javascript const axios = require("axios"); const org_id = "your_org_id"; const page_size = "your_page_size"; const next_token = "your_next_token"; // Optional, use if needed const access_token = "your_bearer_token"; const url = `https://api.m3ter.com/organizations/${org_id}/accounts?pageSize=${page_size}&nextToken=${next_token}`; const headers = { Authorization: `Bearer ${access_token}`, }; axios .get(url, { headers }) .then((response) => { if (response.status === 200) { const accounts = response.data; console.log(accounts); } else { console.log(`Error: ${response.status}`); } }) .catch((error) => { console.error(`Error: ${error.response.status}`); }); ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. ### C++ ```C++ #include <iostream> #include <string> #include <sstream> #include <curl/curl.h> #include <json/json.h> size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } int main() { std::string org_id = "your_org_id"; std::string page_size = "your_page_size"; std::string next_token = "your_next_token"; // Optional, use if needed std::string access_token = "your_bearer_token"; std::string url = "https://api.m3ter.com/organizations/" + org_id + "/accounts?pageSize=" + page_size + "&nextToken=" + next_token; std::string auth_header = "Authorization: Bearer " + access_token; std::string read_buffer; CURL* curl = curl_easy_init(); if(curl) { struct curl_slist* headers = NULL; headers = curl_slist_append(headers, auth_header.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); if (response_code == 200) { Json::Value jsonData; Json::CharReaderBuilder jsonReader; std::string errs; std::istringstream iss(read_buffer); if (Json::parseFromStream(jsonReader, iss, &jsonData, &errs)) { std::cout << jsonData << std::endl; } } else { std::cout << "Error: " << response_code << std::endl; } } curl_easy_cleanup(curl); curl_slist_free_all(headers); } return 0; } ``` Replace `{orgId}`, `{pageSize}`, `{nextToken}`, and `{access_token}` with your Organization ID, desired page size, next token _(if needed)_, and Bearer Token respectively. --- # Integrations Webhook API Example A major benefit of using m3ter is that it seamlessly integrates with your current technology stack. You can create webhook destinations to link you integrations using the API, or via the Console: - This section provides a worked example showing you how to set up a Webhook via the API. - See [Creating and Managing Destinations](https://www.m3ter.com/docs/guides/integrations/setting-up-native-integrations/creating-and-managing-destinations) in the m3ter documentation for instructions on using the Console. ## Step 1: Create a Service User and Generate Access Keys 1. **Create a Service User**: Log in to the m3ter Console, go to **Settings**, **Access** then **Service Users** tab, and create a Service User. To enable API calls, grant the user **Administrator** permissions. 2. **Generate Access Keys**: In the Console, open the **Service User Details** page for the Service User by clicking on the **NAME** hotlink text. Select **Generate Access Key** to generate an **Access Key id** and **Api Secret**. Make sure you copy the **Api Secret** because it is only visible at the time of creation. For further guidance on completing **Step 1**, see [Creating and Configuring Service Users](https://www.m3ter.com/docs/guides/organization-and-access-management/managing-users/creating-and-configuring-service-users) in our main user Documentation. ## Step 2: Obtain a Bearer Token using Basic Auth We implement the OAuth 2.0 Client Credentials Grant authentication flow for Service User Authentication. Submit a request to the m3ter OAuth Client Credentials authentication flow, using your concatenated **Access Key id** and **Api Secret** to obtain a Bearer Token for your Service User. Here's an example in Python code: ```python import requests import base64 # Replace these with your Access Key id and Api Secret access_key_id = 'your_access_key_id' api_secret = 'your_api_secret' # Encode the Access Key id and Api Secret in base64 format credentials = base64.b64encode(f'{access_key_id}:{api_secret}'.encode('utf-8')).decode('utf-8') # Set the m3ter token endpoint URL token_url = 'https://api.m3ter.com/oauth/token' # Set the headers for the request headers = { 'Authorization': f'Basic {credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } # Set the payload for the request payload = { 'grant_type': 'client_credentials' } # Send the request to obtain the Bearer Token response = requests.post(token_url, headers=headers, data=payload) # Check if the request was successful if response.status_code == 200: # Extract the Bearer Token from the response bearer_token = response.json()['access_token'] print(f'Bearer Token: {bearer_token}') else: print(f'Error: {response.status_code} - {response.text}') ``` Replace `your_access_key_id` and `your_api_secret` with your actual **Access Key id** and **Api Secret**. Run the script, and if successful, it will print the Bearer Token. ## Step 3: Create a Webhook (Destination) After obtaining the Bearer Token, you can use it to authorize your API calls. Here's a Python example of creating a webhook: ```python import requests import json # API endpoint url = "https://api.m3ter.com/organizations/{orgId}/integrationdestinations/webhooks" # replace {orgId} with your organization's UUID # Headers headers = { "Content-Type": "application/json", "Authorization": f"Bearer {bearer_token}" # replace with your actual Bearer Token } # Request body payload = { "url": "https://your-webhook-listener.com", # replace with your actual webhook listener URL "credentials": { "type": "M3TER_SIGNED_REQUEST", "apiKey": access_key_id, # replace with your actual API key "secret": api_secret # replace with your actual secret } } # Make the POST request response = requests.post(url, headers=headers, data=json.dumps(payload)) # Print the response print(response.json()) ``` ## Step 4: Validate Incoming Requests Once your webhook is set up, you'll want to validate incoming requests to ensure they're coming from m3ter. All requests we make to your webhook are signed by us. When you receive a request on your configured endpoint, validate the `X-m3ter-signature` header by preparing a payload string that you sign with your API secret. You must concatenate the following data using a pipe '|' separator to compute the payload: - url - query string - Currently, there's no support for passing in query parameters. For now, you can hard code to this string: '{}' - API Key - provided in the `X-m3ter-apikey` header. - timestamp - provided in the `X-m3ter-timestamp` header. - body - the request body. You can now set up and validate webhooks using the m3ter Console and API. Always refer to the latest [m3ter documentation](https://www.m3ter.com/docs) for accurate and up to date information. --- # Authentication <!-- ReDoc-Inject: <security-definitions> -->
Maven plugin to verify a provider [version 2.1.9+] ================================================== Maven plugin for verifying pacts against a provider. The Maven plugin provides a `verify` goal which will verify all configured pacts against your provider. ## To Use It ### 1. Add the pact-jvm-provider-maven plugin to your `build` section of your pom file. ```xml <build> [...] <plugins> [...] <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> </plugin> [...] </plugins> [...] </build> ``` ### 2. Define the pacts between your consumers and providers You define all the providers and consumers within the configuration element of the maven plugin. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <!-- You can define as many as you need, but each must have a unique name --> <serviceProvider> <name>provider1</name> <!-- All the provider properties are optional, and have sensible defaults (shown below) --> <protocol>http</protocol> <host>localhost</host> <port>8080</port> <path>/</path> <consumers> <!-- Again, you can define as many consumers for each provider as you need, but each must have a unique name --> <consumer> <name>consumer1</name> <!-- currently supports a file path using pactFile or a URL using pactUrl --> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### 3. Execute `mvn pact:verify` You will have to have your provider running for this to pass. ## Verifying all pact files in a directory for a provider. [2.1.10+] You can specify a directory that contains pact files, and the Pact plugin will scan for all pact files that match that provider and define a consumer for each pact file in the directory. Consumer name is read from contents of pact file. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <!-- You can define as many as you need, but each must have a unique name --> <serviceProvider> <name>provider1</name> <!-- All the provider properties are optional, and have sensible defaults (shown below) --> <protocol>http</protocol> <host>localhost</host> <port>8080</port> <path>/</path> <pactFileDirectory>path/to/pacts</pactFileDirectory> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Enabling insecure SSL [version 2.2.8+] For providers that are running on SSL with self-signed certificates, you need to enable insecure SSL mode by setting `<insecure>true</insecure>` on the provider. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <pactFileDirectory>path/to/pacts</pactFileDirectory> <insecure>true</insecure> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Specifying a custom trust store [version 2.2.8+] For environments that are running their own certificate chains: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <pactFileDirectory>path/to/pacts</pactFileDirectory> <trustStore>relative/path/to/trustStore.jks</trustStore> <trustStorePassword>changeit</trustStorePassword> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` `trustStore` is either relative to the current working (build) directory. `trustStorePassword` defaults to `changeit`. NOTE: The hostname will still be verified against the certificate. ## Modifying the requests before they are sent Sometimes you may need to add things to the requests that can't be persisted in a pact file. Examples of these would be authentication tokens, which have a small life span. The Pact Maven plugin provides a request filter that can be set to a Groovy script on the provider that will be called before the request is made. This script will receive the HttpRequest bound to a variable named `request` prior to it being executed. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <requestFilter> // This is a Groovy script that adds an Authorization header to each request request.addHeader('Authorization', 'oauth-token eyJhbGciOiJSUzI1NiIsIm...') </requestFilter> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` __*Important Note:*__ You should only use this feature for things that can not be persisted in the pact file. By modifying the request, you are potentially modifying the contract from the consumer tests! ## Modifying the HTTP Client Used [version 2.2.4+] The default HTTP client is used for all requests to providers (created with a call to `HttpClients.createDefault()`). This can be changed by specifying a closure assigned to createClient on the provider that returns a CloseableHttpClient. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <createClient> // This is a Groovy script that will enable the client to accept self-signed certificates import org.apache.http.ssl.SSLContextBuilder import org.apache.http.conn.ssl.NoopHostnameVerifier import org.apache.http.impl.client.HttpClients HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()) .setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, { x509Certificates, s -> true }) .build()) .build() </createClient> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ## Turning off URL decoding of the paths in the pact file [version 3.3.3+] By default the paths loaded from the pact file will be decoded before the request is sent to the provider. To turn this behaviour off, set the system property `pact.verifier.disableUrlPathDecoding` to `true`. __*Important Note:*__ If you turn off the url path decoding, you need to ensure that the paths in the pact files are correctly encoded. The verifier will not be able to make a request with an invalid encoded path. ## Plugin Properties The following plugin properties can be specified with `-Dproperty=value` on the command line or in the configuration section: |Property|Description| |--------|-----------| |pact.showStacktrace|This turns on stacktrace printing for each request. It can help with diagnosing network errors| |pact.showFullDiff|This turns on displaying the full diff of the expected versus actual bodies [version 3.3.6+]| |pact.filter.consumers|Comma seperated list of consumer names to verify| |pact.filter.description|Only verify interactions whose description match the provided regular expression| |pact.filter.providerState|Only verify interactions whose provider state match the provided regular expression. An empty string matches interactions that have no state| Example in the configuration section: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> <configuration> <pact.showStacktrace>true</pact.showStacktrace> </configuration> </configuration> </plugin> ``` ## Provider States For each provider you can specify a state change URL to use to switch the state of the provider. This URL will receive the providerState description from the pact file before each interaction via a POST. The stateChangeUsesBody controls if the state is passed in the request body or as a query parameter. These values can be set at the provider level, or for a specific consumer. Consumer values take precedent if both are given. ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <stateChangeUsesBody>false</stateChangeUsesBody> <!-- defaults to true --> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/provider1-consumer1-pact.json</pactFile> <stateChangeUrl>http://localhost:8080/tasks/pactStateChangeForConsumer1</stateChangeUrl> <stateChangeUsesBody>false</stateChangeUsesBody> <!-- defaults to true --> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` If the `stateChangeUsesBody` is not specified, or is set to true, then the provider state description will be sent as JSON in the body of the request. If it is set to false, it will passed as a query parameter. As for normal requests (see Modifying the requests before they are sent), a state change request can be modified before it is sent. Set `stateChangeRequestFilter` to a Groovy script on the provider that will be called before the request is made. #### Teardown calls for state changes [version 3.2.5/2.4.7+] You can enable teardown state change calls by setting the property `<stateChangeTeardown>true</stateChangeTeardown>` on the provider. This will add an `action` parameter to the state change call. The setup call before the test will receive `action=setup`, and then a teardown call will be made afterwards to the state change URL with `action=teardown`. ## Verifying pact files from a pact broker [version 3.1.1+/2.3.1+] You can setup your build to validate against the pacts stored in a pact broker. The pact plugin will query the pact broker for all consumers that have a pact with the provider based on its name. To use it, just configure the `pactBrokerUrl` or `pactBroker` value for the provider with the base URL to the pact broker. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBrokerUrl>http://pact-broker:5000/</pactBrokerUrl> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### Verifying pacts from an authenticated pact broker [version 3.3.5+] If your pact broker requires authentication (basic authentication is only supported), you can configure the username and password to use by configuring the `authentication` element of the `pactBroker` element of your provider. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBroker> <url>http://pactbroker:1234</url> <authentication> <username>test</username> <password>test</password> </authentication> </pactBroker> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` ### Verifying pacts from an pact broker that match particular tags [version 3.3.5+] If your pacts in your pact broker have been tagged, you can set the tags to fetch by configuring the `tags` element of the `pactBroker` element of your provider. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>provider1</name> <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl> <pactBroker> <url>http://pactbroker:1234</url> <tags> <tag>TEST</tag> <tag>DEV</tag> </tags> </pactBroker> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` This example will fetch and validate the pacts for the TEST and DEV tags. ## Filtering the interactions that are verified You can filter the interactions that are run using three properties: `pact.filter.consumers`, `pact.filter.description` and `pact.filter.providerState`. Adding `-Dpact.filter.consumers=consumer1,consumer2` to the command line or configuration section will only run the pact files for those consumers (consumer1 and consumer2). Adding `-Dpact.filter.description=a request for payment.*` will only run those interactions whose descriptions start with 'a request for payment'. `-Dpact.filter.providerState=.*payment` will match any interaction that has a provider state that ends with payment, and `-Dpact.filter.providerState=` will match any interaction that does not have a provider state. # Verifying a message provider [version 2.2.12+] The Maven plugin has been updated to allow invoking test methods that can return the message contents from a message producer. To use it, set the way to invoke the verification to `ANNOTATED_METHOD`. This will allow the pact verification task to scan for test methods that return the message contents. Add something like the following to your maven pom file: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>messageProvider</name> <verificationType>ANNOTATED_METHOD</verificationType> <!-- packagesToScan is optional, but leaving it out will result in the entire test classpath being scanned. Set it to the packages where your annotated test method can be found. --> <packagesToScan> <packageToScan>au.com.example.messageprovider.*</packageToScan> </packagesToScan> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/messageprovider-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> </configuration> </plugin> ``` Now when the pact verify task is run, will look for methods annotated with `@PactVerifyProvider` in the test classpath that have a matching description to what is in the pact file. ```groovy class ConfirmationKafkaMessageBuilderTest { @PactVerifyProvider('an order confirmation message') String verifyMessageForOrder() { Order order = new Order() order.setId(10000004) order.setExchange('ASX') order.setSecurityCode('CBA') order.setPrice(BigDecimal.TEN) order.setUnits(15) order.setGst(new BigDecimal('15.0')) odrer.setFees(BigDecimal.TEN) def message = new ConfirmationKafkaMessageBuilder() .withOrder(order) .build() JsonOutput.toJson(message) } } ``` It will then validate that the returned contents matches the contents for the message in the pact file. ## Changing the class path that is scanned By default, the test classpath is scanned for annotated methods. You can override this by setting the `classpathElements` property: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <serviceProviders> <serviceProvider> <name>messageProvider</name> <verificationType>ANNOTATED_METHOD</verificationType> <consumers> <consumer> <name>consumer1</name> <pactFile>path/to/messageprovider-consumer1-pact.json</pactFile> </consumer> </consumers> </serviceProvider> </serviceProviders> <classpathElements> <classpathElement> build/classes/test </classpathElement> </classpathElements> </configuration> </plugin> ``` # Publishing pact files to a pact broker [version 3.2.0+] The pact maven plugin provides a `publish` mojo that can publish all pact files in a directory to a pact broker. To use it, you need to add a publish configuration to the POM that defines the directory where the pact files are and the URL to the pact broker. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.8</version> <configuration> <pactDirectory>path/to/pact/files</pactDirectory> <!-- Defaults to ${project.build.directory}/pacts --> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <projectVersion>1.0.100</projectVersion> <!-- Defaults to ${project.version} --> <trimSnapshot>true</trimSnapshot> <!-- Defaults to false --> </configuration> </plugin> ``` You can now execute `mvn pact:publish` to publish the pact files. _NOTE:_ The pact broker requires a version for all published pacts. The `publish` task will use the version of the project by default, but can be overwritten with the `projectVersion` property. Make sure you have set one otherwise the broker will reject the pact files. _NOTE_: By default, the pact broker has issues parsing `SNAPSHOT` versions. You can configure the publisher to automatically remove `-SNAPSHOT` from your version number by setting `trimSnapshot` to true. This setting does not modify non-snapshot versions. ## Publishing to an authenticated pact broker [version 3.3.9+] For an authenticated pact broker, you can pass in the credentials with the `pactBrokerUsername` and `pactBrokerPassword` properties. Currently it only supports basic authentication. For example: ```xml <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.9</version> <configuration> <pactBrokerUrl>http://pactbroker:1234</pactBrokerUrl> <pactBrokerUsername>USERNAME</pactBrokerUsername> <pactBrokerPassword>PASSWORD</pactBrokerPassword> </configuration> </plugin> ```
A libray which helps to structure parsing and validation of URL encoded HTTP forms.
Parses URL query strings into predefined object models. Handles complex data structures and transforms end values into objects. A powerful, easy to use tool.
An implementation of the WHATWG URL Standard's URL API and parsing machinery
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.
Ksoup is a Kotlin Multiplatform library for working with HTML and XML, and offers an easy-to-use API for URL fetching, data parsing, extraction, and manipulation using DOM and CSS selectors.