# Postman Collection
source: https://developer.mastercard.com/mastercard-threat-intelligence/documentation/developer-tools/postman-collection/index.md

## Overview {#overview}

[Postman](https://www.postman.com/) is an application for easy RESTful API exploration. You can use Postman to test API calls multiple times without having to write code. You can save multiple sets of credentials to quickly test an API's calls in the sandbox and production environments.

This page shows how to setup a self-contained Postman collection for the Mastercard Threat Intelligence API. It performs the full **OAuth 2.0 / FAPI 2.0** flow (`private_key_jwt` client
authentication + **DPoP** proofs), mirroring the Java `oauth2-client-java`
library. All signing runs **synchronously** (the `jsrsasign` library is embedded
in the collection), so it works on any Postman version --- including older runtimes
that don't await asynchronous pre-request scripts.

## Files {#files}

* `mti-api.postman_collection.json` --- the requests + the embedded auth engine (**contains no credentials**).
* `mti-sandbox.postman_environment.json` --- **Sandbox** environment (endpoints preset; you add your credentials).
* `mti-production.postman_environment.json` --- **Production** environment (endpoints preset; you add your credentials).

> Download [mti-api-postman-collection.zip](https://static.developer.mastercard.com/content/mastercard-threat-intelligence/uploads/mti-api-postman-collection.zip)

## Prerequisites {#prerequisites}

* Postman.
* A **Mastercard Developers** project with the Threat Intelligence API enabled, which gives you a **Client ID** , a **Key ID (`kid`)** , your granted **scopes** , and a **signing key** (a `.p12`/PKCS#12 keystore or a PEM private key).
* `openssl` --- only if your signing key is a `.p12` you need to convert to PEM.

## Setup (bring your own credentials) {#setup-bring-your-own-credentials}

### 1. Get your signing key as a PEM private key {#1-get-your-signing-key-as-a-pem-private-key}

Tip: Already have a PEM private key (`-----BEGIN PRIVATE KEY-----` or `-----BEGIN RSA PRIVATE KEY-----`)? Skip this step.

The client assertion is signed with your RSA private key (`PS256`). If your key is
a PKCS#12 (`.p12`/`.pfx`) keystore, convert it to PEM:

```sh
openssl pkcs12 -in path/to/your-signing-key.p12 \
  -nodes -nocerts -passin pass:'YOUR_P12_PASSWORD' \
  | openssl pkey -out client-private-key.pem
```

On OpenSSL 3.x, if the output is empty, add `-legacy` to the `pkcs12` step:

```sh
openssl pkcs12 -legacy -in path/to/your-signing-key.p12 \
  -nodes -nocerts -passin pass:'YOUR_P12_PASSWORD' \
  | openssl pkey -out client-private-key.pem
```

> The PEM is a **secret** --- do not commit or share it.

### 2. Import into Postman {#2-import-into-postman}

1. **Import** the collection `mti-api.postman_collection.json`.
2. **Import** the environment for your target --- `mti-sandbox.postman_environment.json` or `mti-production.postman_environment.json` (import both if you use both).
3. **Select** the environment ("MTI Sandbox" or "MTI Production") in the top-right selector.

### 3. Fill in your credentials {#3-fill-in-your-credentials}

Edit the environment (set the **CURRENT VALUE** column) and **Save**:

|       Variable        |                                         Set to                                         |
|-----------------------|----------------------------------------------------------------------------------------|
| `clientId`            | Your Mastercard Developers **Client ID**                                               |
| `kid`                 | Your **Key ID** (the `kid` for your signing key)                                       |
| `clientPrivateKeyPem` | The full PEM from step 1 (including the `-----BEGIN/END-----` lines)                   |
| `scopes`              | Comma-separated scopes granted to your project (defaults to the three MTI read scopes) |

The collection signs the client assertion with **PS256** , so your signing key
must be an **RSA** key (Mastercard-issued keys are RSA).

### 4. Sandbox vs production {#4-sandbox-vs-production}

Each environment file already has its endpoints **preset** --- just use the one that
matches where your credentials are registered. For reference:

|    Variable     |                   MTI Sandbox                    |              MTI Production              |
|-----------------|--------------------------------------------------|------------------------------------------|
| `baseUrl`       | `https://sandbox.cyber.mastercard.com`           | `https://cyber.mastercard.com`           |
| `tokenEndpoint` | `https://sandbox.api.mastercard.com/oauth/token` | `https://api.mastercard.com/oauth/token` |
| `issuer`        | `https://sandbox.api.mastercard.com`             | `https://api.mastercard.com`             |

* Your `clientId` / `kid` / key are registered for **one** environment --- use the matching file. A key used against the wrong environment fails at the token step with `invalid_client` ("signature couldn't be verified").
* Confirm these hosts against your Mastercard Developers project if in doubt.
* Leave the auto-managed variables (`accessToken`, `dpop*`, `resource*`) empty; the collection fills them.

### 5. Get an access token, then call the API {#5-get-an-access-token-then-call-the-api}

This is a two-step flow (the token step is its own request so it works on any
Postman version):

1. Open **0. Auth → Get Access Token** and **Send** .
   * FAPI 2.0 requires a DPoP nonce, so the **first** send usually returns `400 use_dpop_nonce`. **Send it again** --- the nonce is captured automatically and the token is fetched and cached.
2. Open any resource request and **Send** .
   * If it returns `use_dpop_nonce` on the first hit, **send again** (the resource nonce is captured automatically).

Re-run **Get Access Token** when the token expires (the collection tells you with
`No valid access token` in the console).

What happens under the hood, all synchronously in the collection pre-request:

1. `jsrsasign` is eval'd from the embedded `jsrsasignSource` variable.
2. A DPoP EC P-256 key pair is generated and persisted (the token is bound to it).
3. For **Get Access Token** : a `private_key_jwt` client assertion + a token DPoP proof are built into the request.
4. For **resource requests** : a per-request DPoP proof is signed and the `Authorization: DPoP <token>` and `DPoP: <proof>` headers are set.

### Requests {#requests}

|                Folder                 |         Request         | Method |                           Path                            |
|---------------------------------------|-------------------------|--------|-----------------------------------------------------------|
| 0. Auth                               | Get Access Token        | POST   | token endpoint (`private_key_jwt` grant)                  |
| Merchant Threat Intelligence          | Merchant Domain Search  | POST   | `/exposures/domains`                                      |
| Payment Ecosystem Threat Intelligence | Search Vulnerabilities  | GET    | `/exposures/vulnerabilities`                              |
| Card Testing                          | Observed Testing Search | POST   | `/threats/observed-testings/searches`                     |
| Card Testing                          | Testing Behavior Search | POST   | `/threats/testing-behaviors/searches`                     |
| Card Testing                          | Transactions Search     | POST   | `/threats/transactions/searches`                          |
| Card Testing                          | Filter Options          | GET    | `/threats/card-testings/filter-options?type=TRANSACTIONS` |

## Variables {#variables}

The collection holds only the embedded library, so it carries **no credentials** .
**Everything else lives in your environment.**

|               Variable                |    Where    |                                      Purpose                                      |
|---------------------------------------|-------------|-----------------------------------------------------------------------------------|
| `jsrsasignSource`                     | collection  | Embedded `jsrsasign` library source (do not edit)                                 |
| `clientId`, `kid`                     | environment | **You set** --- your Client ID + Key ID                                           |
| `clientPrivateKeyPem`                 | environment | **You set** --- PEM private key (secret)                                          |
| `scopes`                              | environment | **You set** --- comma-separated OAuth scopes                                      |
| `baseUrl`                             | environment | Preset per environment (sandbox/production)                                       |
| `tokenEndpoint`, `issuer`             | environment | Preset per environment (sandbox/production)                                       |
| `accessToken`, `accessTokenExp`       | environment | Auto-managed cached token                                                         |
| `dpopPrivateJwk`, `dpopPublicJwk`     | environment | Auto-managed DPoP key pair                                                        |
| `dpopNonceToken`, `dpopNonceResource` | environment | Auto-managed DPoP nonces                                                          |
| `resourceAuth`, `resourceDpop`        | environment | Auto-managed `Authorization`/`DPoP` values (referenced by static request headers) |

## Known limitations \& troubleshooting {#known-limitations--troubleshooting}

* **`Missing required config: ...`** --- set the listed variables in your selected environment (step 3), then re-send.
* **`use_dpop_nonce` on the first send** --- expected for both the token request and the first resource call. Just **send again**; the nonce is captured automatically.
* **`No valid access token` in the console** --- run **0. Auth → Get Access Token** first (send twice if prompted for a nonce), then retry the resource request.
* **`invalid_client` / signature errors** on the token request --- the PEM doesn't match your `clientId`/`kid`, the key isn't registered for that environment, or `tokenEndpoint`/`issuer` point at the wrong host (sandbox vs production).
* **`403` on a resource** --- auth is fine but your project isn't entitled for that endpoint/scope (e.g. issuer-only vs acquirer-only data).
* **Switching credentials or environment** --- clear the auto-managed variables (`accessToken`, `accessTokenExp`, `dpopPrivateJwk`, `dpopPublicJwk`, `dpopNonceToken`, `dpopNonceResource`) so a cached token/key from a previous identity isn't reused, then run **Get Access Token** again.
* **DPoP key rotation** --- deleting `dpopPrivateJwk`/`dpopPublicJwk` forces a new key; the cached token is cleared automatically since it's bound to the old key.
* **`jsrsasignSource is empty`** --- re-import `mti-api.postman_collection.json`.

Note: See the following alternative [Postman tutorial](https://developer.mastercard.com/platform/documentation/developer-tools/postman-collection/) for the generic steps needed to get Mastercard authentication working with the Postman collection.
