> ## Documentation Index
> Fetch the complete documentation index at: https://docs.masterid.co.ug/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get started with the MasterID API in minutes: credentials, catalog, wallet, consent, and your first verification.

This guide walks you through your first end-to-end MasterID integration. You will generate credentials, call the catalog and wallet endpoints, request consent wording, submit a verification, and poll for the final result.

> [!NOTE]
>
> MasterID provides one live API credential pair per workspace. There is no sandbox in this release. Use approved test identities only when testing live services.

**1. Generate credentials and record your Merchant ID**

Open the Developer Console and generate an API Key and API Secret. Securely store both values when first shown. Secrets cannot be recovered after their first display is closed. Record your Merchant ID, but note that it does not authenticate requests.

**2. Set environment variables**

Keep credentials in your server's secret store and read them from environment variables. Never include them in browser JavaScript, public repositories, URLs, analytics, or application logs.

```bash .env theme={null}
MASTERID_API_KEY=your-api-key
MASTERID_API_SECRET=your-api-secret
MASTERID_WEBHOOK_SECRET=your-webhook-secret
```

**3. Call GET /catalog for supported products**

List the verification products available to your workspace, their required fields, and wallet charges.

```bash cURL theme={null}
curl -s https://masterid.me/api/public/v1/catalog \
  -H "X-API-Key: $MASTERID_API_KEY" \
  -H "X-API-Secret: $MASTERID_API_SECRET" \
  -H "Content-Type: application/json"
```

```javascript Node.js theme={null}
const res = await fetch("https://masterid.me/api/public/v1/catalog", {
  headers: {
    "X-API-Key": process.env.MASTERID_API_KEY,
    "X-API-Secret": process.env.MASTERID_API_SECRET,
    "Content-Type": "application/json",
  },
});
const body = await res.json();
console.log(body);
```

```python Python theme={null}
import requests, os
r = requests.get(
    "https://masterid.me/api/public/v1/catalog",
    headers={
        "X-API-Key": os.environ["MASTERID_API_KEY"],
        "X-API-Secret": os.environ["MASTERID_API_SECRET"],
        "Content-Type": "application/json",
    },
)
print(r.json())
```

Use the response to determine which product and fields you need for your use case.

**4. Check GET /wallet before submitting**

Ensure your workspace has sufficient funds before creating a charged verification.

```bash cURL theme={null}
curl -s https://masterid.me/api/public/v1/wallet \
  -H "X-API-Key: $MASTERID_API_KEY" \
  -H "X-API-Secret: $MASTERID_API_SECRET" \
  -H "Content-Type: application/json"
```

```javascript Node.js theme={null}
const res = await fetch("https://masterid.me/api/public/v1/wallet", {
  headers: {
    "X-API-Key": process.env.MASTERID_API_KEY,
    "X-API-Secret": process.env.MASTERID_API_SECRET,
    "Content-Type": "application/json",
  },
});
const body = await res.json();
console.log("Balance:", body.data.balance, body.data.currency);
```

```python Python theme={null}
import requests, os
r = requests.get(
    "https://masterid.me/api/public/v1/wallet",
    headers={
        "X-API-Key": os.environ["MASTERID_API_KEY"],
        "X-API-Secret": os.environ["MASTERID_API_SECRET"],
        "Content-Type": "application/json",
    },
)
data = r.json()["data"]
print("Balance:", data["balance"], data["currency"])
```

**5. Request consent wording**

Before submitting a verification, obtain the data subject's lawful authorisation. Request exact consent wording using the same fields you intend to submit.

```bash cURL theme={null}
curl -s -X POST https://masterid.me/api/public/v1/verifications/consent \
  -H "X-API-Key: $MASTERID_API_KEY" \
  -H "X-API-Secret: $MASTERID_API_SECRET" \
  -H "Content-Type: application/json" \
  --data '{"product":"tin","fields":{"tin":"<APPROVED_TIN>"}}'
```

```javascript Node.js theme={null}
const res = await fetch("https://masterid.me/api/public/v1/verifications/consent", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.MASTERID_API_KEY,
    "X-API-Secret": process.env.MASTERID_API_SECRET,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ product: "tin", fields: { tin: "<APPROVED_TIN>" } }),
});
const body = await res.json();
console.log("Consent text:", body.data.consentText);
```

```python Python theme={null}
import requests, os
r = requests.post(
    "https://masterid.me/api/public/v1/verifications/consent",
    headers={
        "X-API-Key": os.environ["MASTERID_API_KEY"],
        "X-API-Secret": os.environ["MASTERID_API_SECRET"],
        "Content-Type": "application/json",
    },
    json={"product": "tin", "fields": {"tin": "<APPROVED_TIN>"}},
)
print("Consent text:", r.json()["data"]["consentText"])
```

Present the returned `consentText` to the data subject for genuine confirmation. If the identity details change, request fresh wording.

**6. Submit the verification with Idempotency-Key**

Include the exact consent text and set `consentConfirmed` to `true`. Include a unique `Idempotency-Key` header. Store the returned `sessionId`.

```bash cURL theme={null}
curl -s -X POST https://masterid.me/api/public/v1/verifications \
  -H "X-API-Key: $MASTERID_API_KEY" \
  -H "X-API-Secret: $MASTERID_API_SECRET" \
  -H "Idempotency-Key: your-unique-request-id" \
  -H "Content-Type: application/json" \
  --data '{"product":"tin","fields":{"tin":"<APPROVED_TIN>"},"consentConfirmed":true,"consentText":"<EXACT_CONFIRMED_TEXT>"}'
```

```javascript Node.js theme={null}
const res = await fetch("https://masterid.me/api/public/v1/verifications", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.MASTERID_API_KEY,
    "X-API-Secret": process.env.MASTERID_API_SECRET,
    "Idempotency-Key": "your-unique-request-id",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    product: "tin",
    fields: { tin: "<APPROVED_TIN>" },
    consentConfirmed: true,
    consentText: "<EXACT_CONFIRMED_TEXT>",
  }),
});
const body = await res.json();
console.log("Session ID:", body.data.sessionId);
```

```python Python theme={null}
import requests, os
r = requests.post(
    "https://masterid.me/api/public/v1/verifications",
    headers={
        "X-API-Key": os.environ["MASTERID_API_KEY"],
        "X-API-Secret": os.environ["MASTERID_API_SECRET"],
        "Idempotency-Key": "your-unique-request-id",
        "Content-Type": "application/json",
    },
    json={
        "product": "tin",
        "fields": {"tin": "<APPROVED_TIN>"},
        "consentConfirmed": True,
        "consentText": "<EXACT_CONFIRMED_TEXT>",
    },
)
print("Session ID:", r.json()["data"]["sessionId"])
```

**7. Poll for the result or wait for a webhook**

A pending response returns HTTP 202. Poll `GET /verifications/{sessionId}` no more frequently than every 15 seconds, or accept a signed `verification.completed` webhook.

```bash cURL theme={null}
curl -s https://masterid.me/api/public/v1/verifications/<SESSION_ID> \
  -H "X-API-Key: $MASTERID_API_KEY" \
  -H "X-API-Secret: $MASTERID_API_SECRET" \
  -H "Content-Type: application/json"
```

```javascript Node.js theme={null}
const res = await fetch(`https://masterid.me/api/public/v1/verifications/${sessionId}`, {
  headers: {
    "X-API-Key": process.env.MASTERID_API_KEY,
    "X-API-Secret": process.env.MASTERID_API_SECRET,
    "Content-Type": "application/json",
  },
});
const body = await res.json();
console.log("Status:", body.data.status);
```

```python Python theme={null}
import requests, os
r = requests.get(
    f"https://masterid.me/api/public/v1/verifications/{session_id}",
    headers={
        "X-API-Key": os.environ["MASTERID_API_KEY"],
        "X-API-Secret": os.environ["MASTERID_API_SECRET"],
        "Content-Type": "application/json",
    },
)
print("Status:", r.json()["data"]["status"])
```

**8. Activate your merchant account before collecting payments**

Complete merchant activation in the MasterID app before you create collection requests. The Merchant ID alone does not enable collections.

## End-to-end example

The following Node.js and Python scripts request consent, prompt for confirmation, submit a verification, and poll every 15 seconds until a final status is returned.

```javascript verify.js theme={null}
// Node.js 18+ (native fetch)
const BASE = "https://masterid.me/api/public/v1";

async function masteridFetch(path, opts = {}) {
  return fetch(`${BASE}${path}`, {
    ...opts,
    headers: {
      "X-API-Key": process.env.MASTERID_API_KEY,
      "X-API-Secret": process.env.MASTERID_API_SECRET,
      "Content-Type": "application/json",
      ...opts.headers,
    },
  });
}

async function requestConsent(product, fields) {
  const res = await masteridFetch("/verifications/consent", {
    method: "POST",
    body: JSON.stringify({ product, fields }),
  });
  const body = await res.json();
  if (!res.ok) throw new Error(body.error || "Consent request failed");
  return body.data.consentText;
}

async function submitVerification(product, fields, consentText, idempotencyKey) {
  const res = await masteridFetch("/verifications", {
    method: "POST",
    headers: { "Idempotency-Key": idempotencyKey },
    body: JSON.stringify({
      product,
      fields,
      consentConfirmed: true,
      consentText,
    }),
  });
  const body = await res.json();
  if (!res.ok && res.status !== 202) throw new Error(body.error || "Submission failed");
  return body.data.sessionId;
}

async function pollVerification(sessionId) {
  while (true) {
    const res = await masteridFetch(`/verifications/${sessionId}`);
    const body = await res.json();
    const status = body.data.status;
    if (status !== "pending") return body.data;
    await new Promise((r) => setTimeout(r, 15_000));
  }
}

(async () => {
  try {
    const product = "tin";
    const fields = { tin: "<APPROVED_TIN>" };

    const consentText = await requestConsent(product, fields);
    console.log("Consent wording:\n", consentText);

    // Present wording to the data subject and confirm explicitly
    const confirmed = true; // Replace with real confirmation flow
    if (!confirmed) {
      console.log("Consent not confirmed. Exiting.");
      process.exit(0);
    }

    const idempotencyKey = `verify-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
    const sessionId = await submitVerification(product, fields, consentText, idempotencyKey);
    console.log("Session ID:", sessionId);

    const result = await pollVerification(sessionId);
    console.log("Final result:", result.status, result.charged);
  } catch (err) {
    console.error(err.message);
    process.exit(1);
  }
})();
```

```python verify.py theme={null}
# Python 3.10+ (requests)
import os, time, uuid
import requests

BASE = "https://masterid.me/api/public/v1"
AUTH_HEADERS = {
    "X-API-Key": os.environ["MASTERID_API_KEY"],
    "X-API-Secret": os.environ["MASTERID_API_SECRET"],
    "Content-Type": "application/json",
}


def request_consent(product, fields):
    r = requests.post(
        f"{BASE}/verifications/consent",
        headers=AUTH_HEADERS,
        json={"product": product, "fields": fields},
    )
    r.raise_for_status()
    return r.json()["data"]["consentText"]


def submit_verification(product, fields, consent_text, idempotency_key):
    headers = {**AUTH_HEADERS, "Idempotency-Key": idempotency_key}
    r = requests.post(
        f"{BASE}/verifications",
        headers=headers,
        json={
            "product": product,
            "fields": fields,
            "consentConfirmed": True,
            "consentText": consent_text,
        },
    )
    if not r.ok and r.status_code != 202:
        r.raise_for_status()
    return r.json()["data"]["sessionId"]


def poll_verification(session_id):
    while True:
        r = requests.get(
            f"{BASE}/verifications/{session_id}",
            headers=AUTH_HEADERS,
        )
        r.raise_for_status()
        data = r.json()["data"]
        if data["status"] != "pending":
            return data
        time.sleep(15)


if __name__ == "__main__":
    product = "tin"
    fields = {"tin": "<APPROVED_TIN>"}

    consent_text = request_consent(product, fields)
    print("Consent wording:\n", consent_text)

    # Present wording to the data subject and confirm explicitly
    confirmed = True  # Replace with real confirmation flow
    if not confirmed:
        print("Consent not confirmed. Exiting.")
        exit(0)

    idempotency_key = str(uuid.uuid4())
    session_id = submit_verification(product, fields, consent_text, idempotency_key)
    print("Session ID:", session_id)

    result = poll_verification(session_id)
    print("Final result:", result["status"], result["charged"])
```

## Next steps

* [Authentication](https://docs.masterid.co.ug/authentication.md): learn how to protect and rotate credentials.
* [Products](https://docs.masterid.co.ug/products.md): review all supported verification products and required fields.
* [Guides](https://docs.masterid.co.ug/guides/verifications.md): explore detailed flows for verifications, collections, and webhooks.
* [API reference](https://docs.masterid.co.ug/api-reference/overview.md): browse endpoint-level documentation.


## Related topics

- [MasterID Integration API](https://docs.masterid.co.ug/index.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.