Department 02
Six operations across five resources. The contract is versioned in the path and describes only what's actually public — no response contains raw personal information without a role for it.
Every call requires a Bearer token issued by Zitadel (OIDC). The public app uses PKCE. A B2B integration uses a service account whose scopes decide which operations are available.
curl -sS https://api.marketmute.com/v1/me/identity \
-H "Authorization: Bearer $MARKETMUTE_TOKEN" \
-H "Accept: application/json"
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{ "error": "unauthorized" }
The paths below are relative to the base URL. Fields marked as masked are never returned in plain text.
Lists the signed-in person's identifiers in masked form. Verification status and active/inactive come along — the value doesn't.
curl -sS https://api.marketmute.com/v1/me/identity \
-H "Authorization: Bearer $MARKETMUTE_TOKEN"
[
{
"id": "3f2b9c40-0d1e-4a77-9c2e-1b0a5d6e7f81",
"type": "EMAIL_PRIVATE",
"scope": "PRIVATE",
"verified": "PASSED",
"active": true
}
]
Adds an identifier — email, phone number, or name. Responds 201 without echoing the value back.
{
"type": "EMAIL_PRIVATE",
"value": "anna@example.se",
"scope": "PRIVATE"
}
HTTP/1.1 201 Created
| Field | Requirement | Description |
|---|---|---|
| type | Required | Type of identifier, e.g. EMAIL_PRIVATE. |
| value | Required | The identifier itself. Never stored unprotected. |
| scope | Optional | Private or professional use. |
Sends a verification code to the identifier. Only once the code is confirmed can the identifier be used in a rights case.
{ "method": "EMAIL_OTP" }
HTTP/1.1 200 OK
// The code has been sent. The status word in the
// response just describes what actually happened.
Classifies an incoming number ahead of mobile protection. The response carries a category and a confidence score — never a full identity.
curl -sS -G https://api.marketmute.com/v1/mobile/shield/caller \
--data-urlencode "number=+46700000000" \
-H "Authorization: Bearer $MARKETMUTE_TOKEN"
{
"category": "DIRECT_MARKETING",
"confidence": 0.82,
"source": "caller-intelligence"
}
| Category | Meaning |
|---|---|
| DIRECT_MARKETING | Direct marketing. |
| MEETING_BOOKING | Meeting booking on behalf of another party. |
| RECRUITMENT | Recruitment. |
| SURVEY | Survey. |
| FRAUD_REPORTED | Reported as a fraud attempt. |
| LEGITIMATE_BUSINESS | Business contact with no marketing purpose. |
| UNKNOWN | Not enough signal to classify. |
B2B check of ONE identifier before sending. Only accepts a hash you calculate yourself — never a plaintext email or phone number.
Its own authentication: an API key (mm_live_… / mm_test_…) in the Authorization header — not the same Zitadel token as above. Its own rate limit, its own status-code table, and the honest 501 state (the matching still lacks a per-sender index) are covered in full in department 03.
The same check for up to 10,000 hashes in one call. Same authentication, hash requirements, and 501 state as /suppression/check.
A batch over 10,000 hashes is rejected in full — nothing is truncated. See department 03 for the full limits.
The contract lists the successful responses per operation. Error responses follow ordinary HTTP semantics and look the same across the whole API.
| Code | Meaning | What you do |
|---|---|---|
| 200 | The request succeeded. | Read the response. |
| 201 | The resource was created. | No response body to read. |
| 400 | The request is malformed or missing required fields. | Fix the call. Don't retry it unchanged. |
| 401 | The token is missing, expired, or invalid. | Get a new token. |
| 403 | The token lacks the scope the operation requires. | Review the service account's scopes. |
| 404 | The resource doesn't exist, or belongs to someone else. | Check the id. |
| 429 | The rate limit was exceeded. | Wait before the next call; see department 03. |
| 500 | An unexpected error on our side. | Retry the call after a short pause. |
Don't write the types by hand. Clients are generated from the contract file in packages/contracts/openapi/marketmute.openapi.yaml with scripts/generate-contracts.sh, so they never get to drift from the API.
import { createClient } from "@marketmute/contracts";
const client = createClient(token);
const identifiers = await client.listIdentifiers();
var client = new MarketMuteClient(token);
var identifiers = await client.ListIdentifiersAsync();