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

# POST /v2/screen

> Cheap labels + consensus risk in one call — server-side mirror of x402 /screen, billed via subscription quota.

<Note>
  **Auth:** Required · **Cost:** \$0.10 per call (USD ledger) · **Provider:** Aegis only (Tier 0+1+2 — no graph traversal, no external providers)
</Note>

The **same SQL queries** that x402-api's
[`$0.10 GET /screen/{chain}/{address}`](/endpoints/screen) runs, billed
against your USD balance instead of via on-chain USDC.

Designed for high-volume B2B integrations: a wallet running a
pre-send screen on every user-typed address will use this endpoint,
not [`/v2/check-address`](/api-reference/v2-check-address).  Same
compute as x402's `/screen`, but settled off-chain against your USD
balance instead of an on-chain USDC transfer — no per-call settlement
gas to amortise.

## Request

```bash theme={null}
curl -X POST https://api.aegis-kyt.com/v2/screen \
  -H "Authorization: Bearer aeg_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TScSLnUodZVsgoGchZspDoimDjDB9bwqVv",
    "network": "TRON"
  }'
```

| Field     | Type   | Notes                                                                                                                                    |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `address` | string | EVM hex (auto-lowercased) or base58 (TRON/BTC/SOL — case preserved)                                                                      |
| `network` | string | Case-insensitive.  Must be in Aegis ingestion footprint — currently **BSC, ETH, TRON**.  Other networks return `400 unsupported_network` |

There is **no `provider` field** — light always runs Aegis (Tier
0+1+2).  If you need provider\_b / provider\_a or full 4-tier (with 1-hop +
BFS), use [`POST /v2/check-address`](/api-reference/v2-check-address).

Optional headers:

| Header                         | Purpose                                                                                                 |
| ------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `Idempotency-Key: <≤64 chars>` | Replay-safe within 24h.  Same key + same body → cached response, no charge.  Different body → HTTP 409. |

## Response 200

```json theme={null}
{
  "schema_version": 4,
  "address": "TScSLnUodZVsgoGchZspDoimDjDB9bwqVv",
  "network": "TRON",
  "provider": "Aegis",
  "coverage": {
    "data_available":  true,
    "label_count":     3,
    "source_count":    3,
    "sdn_checked":     true,
    "consensus_found": true,
    "tiers":           ["sdn", "consensus"],
    "graph_analysed":  false
  },
  "verdict": {
    "ok":                  true,
    "risk_level":          "medium",
    "risk_score":          50,
    "risk_categories":     ["sanctions_exposure"],
    "consensus_found":     true,
    "source_count":        3,
    "confidence":          50,
    "primary_source_slug": "graphsense-tagpacks",
    "label":               "Some Exchange",
    "sdn_match":           null,
    "labels": [
      {
        "source":        "provider_a-verdicts",
        "source_name":   "Third-party KYT consensus provider A",
        "label":         null,
        "category":      "sanctions_exposure",
        "confidence":    78,
        "source_url":    "https://…",
        "first_seen_at": "2025-09-12T00:00:00Z",
        "last_seen_at":  "2026-04-29T00:00:00Z"
      }
    ],
    "risk_category_detail": [
      {
        "slug":             "exchange",
        "risk_level":       "low",
        "severity":         10,
        "confidence":       88.9,
        "source_count":     8,
        "max_trust_weight": 100,
        "sources":          ["okx-por", "tronscan-api", "provider_a-counterparties"]
      },
      {
        "slug":             "sanctions_exposure",
        "risk_level":       "medium",
        "severity":         45,
        "confidence":       27.0,
        "source_count":     1,
        "max_trust_weight": 60,
        "sources":          ["provider_a-verdicts"]
      }
    ],
    "smart_contract": {
      "is_contract":            false,
      "token_contract":         false,
      "symbol":                 null,
      "decimals":               null,
      "is_well_known":          false,
      "logo_url":               null,
      "tags":                   [],
      "primary_entity":         null,
      "complementary_entities": []
    }
  },
  "billing": {
    "model":              "ledger",
    "currency":           "USD",
    "charged_usd":        0.1,
    "balance_usd":        15.9,
    "monthly_spent_usd":  0.1,
    "monthly_cap_usd":    null,
    "replay":             false
  },
  "elapsed_ms": 60
}
```

### `coverage` — read this before `risk_level`

`risk_level: "none"` means **we found no risk signal**, which is not the
same as "this address is clean".  For an address nobody has ever
enriched, a Tier 0+1+2 screen has nothing to say, and the honest verdict
shape for that is `none` / `0`.

`coverage.data_available` is the field that tells the two apart:

```json theme={null}
"coverage": {
  "data_available":  false,
  "label_count":     0,
  "source_count":    0,
  "sdn_checked":     true,
  "consensus_found": false,
  "tiers":           ["sdn", "consensus"],
  "graph_analysed":  false
}
```

<Warning>
  Do **not** gate a transfer on `risk_level === "none"` alone.  Treat
  `coverage.data_available: false` as *unknown*, not as *clean* — decide
  in your own policy whether unknown means allow, review, or escalate to
  [`/v2/check-address`](/api-reference/v2-check-address), which runs the
  full 4-tier analysis including the address's counterparties.
</Warning>

`graph_analysed` is always `false` here by design — this endpoint never
looks at who the address transacts with.  An address that screens `none`
can still come back `high` from `/v2/check-address` because its
counterparties are what carry the risk.  That is not a contradiction
between two products; it is two different questions.

| Field             | Type      | Notes                                                                               |
| ----------------- | --------- | ----------------------------------------------------------------------------------- |
| `data_available`  | bool      | `false` → we hold no SDN hit, no consensus row and no label claims for this address |
| `label_count`     | int       | Rows in `verdict.labels[]`                                                          |
| `source_count`    | int       | Distinct sources behind the consensus verdict                                       |
| `sdn_checked`     | bool      | Always `true` — the sanctions lookup always runs                                    |
| `consensus_found` | bool      | Mirror of `verdict.consensus_found`                                                 |
| `tiers`           | string\[] | Analysis tiers this call ran                                                        |
| `graph_analysed`  | bool      | Always `false` — no 1-hop, no BFS                                                   |

Quota is charged whether or not we had data — the customer paid for the
lookup, not for a guarantee of a hit.

### Source naming

`labels[].source` / `source_name` identify the *class* of source, not
always the vendor.  Commercial KYT feeds we license are returned under
neutral `provider_x` aliases; sanctions registries, block explorers,
community feeds and our own curator entries are named directly, because
their identity is the evidence.

`label` is a counterparty **name** or `null`.  It is deliberately `null`
whenever the underlying claim carries a risk annotation rather than an
identity — you will never receive a vendor's internal verdict string in
that field.

### `verdict` object

| Field                    | Type               | Notes                                                                                                                                                                                                                                                                                                |
| ------------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`                     | bool               | Always `true` when status is 200                                                                                                                                                                                                                                                                     |
| `risk_level`             | enum \| null       | `none` / `low` / `medium` / `high` / `critical` / `sanctioned`                                                                                                                                                                                                                                       |
| `risk_score`             | int 0..100 \| null | Aggregated across sources                                                                                                                                                                                                                                                                            |
| `risk_categories`        | string\[]          | Slugs only — see [risk categories](/reference/risk-categories)                                                                                                                                                                                                                                       |
| `consensus_found`        | bool               | `false` → no consensus row exists for this address                                                                                                                                                                                                                                                   |
| `source_count`           | int                | How many sources contributed                                                                                                                                                                                                                                                                         |
| `confidence`             | int 0..100 \| null | Noisy-OR confidence in the **primary risk category** — i.e. how likely the finding that drove `risk_level`/`risk_score` is.  Not a measure of how many sources agree; use `source_count` for that.  A low `risk_level` with a low `confidence` means "weak signal, and we are not sure of even that" |
| `primary_source_slug`    | string \| null     | Highest-trust source contributing to the verdict                                                                                                                                                                                                                                                     |
| `label`                  | string \| null     | Best human-readable NAME, or `null` when every claim is a risk annotation rather than an identity                                                                                                                                                                                                    |
| `sdn_match`              | object \| null     | Tier-0 sanctions hit (OFAC SDN / UK OFSI / EU)                                                                                                                                                                                                                                                       |
| `labels[]`               | array              | Per-source label rows — same shape as x402 [`/screen`](/endpoints/screen).  See **Source naming** above                                                                                                                                                                                              |
| `smart_contract`         | object             | Contract / token metadata for the address.  Always present; `is_contract: false` for ordinary wallets                                                                                                                                                                                                |
| `risk_category_detail[]` | array              | Per-category evidence — see **Reading the category evidence** below                                                                                                                                                                                                                                  |

### Reading the category evidence

`risk_categories` tells you *what* we concluded.  `risk_category_detail[]`
tells you *how well-supported each part of that conclusion is*, which is
where source disagreement becomes visible.  Real example — a licensed
exchange with 13 sources:

| slug                 | confidence | source\_count | max\_trust\_weight |
| -------------------- | ---------- | ------------- | ------------------ |
| `exchange`           | 88.9       | 8             | 100                |
| `sanctions_exposure` | 27.0       | 1             | 60                 |

The row-level verdict is `low`/`20`, driven by `sanctions_exposure` — but
the identity is corroborated eight ways by high-trust sources, while the
risk flag rests on a single mid-trust one.  Both facts matter to whoever
is deciding, and only the first one is visible from `risk_level` alone.

| Field              | Type                 | Notes                                                             |
| ------------------ | -------------------- | ----------------------------------------------------------------- |
| `slug`             | string               | Category slug — see [risk categories](/reference/risk-categories) |
| `risk_level`       | string \| null       | This category's own level (not the address's)                     |
| `severity`         | int \| null          | Taxonomy severity of the category                                 |
| `confidence`       | float 0..100 \| null | Noisy-OR probability this category applies                        |
| `source_count`     | int \| null          | Sources that attributed THIS category                             |
| `max_trust_weight` | int \| null          | Trust weight of the best source behind it                         |
| `sources[]`        | string\[]            | Source slugs, under the same aliasing rules as `labels[]`         |

<Note>
  A single-source, mid-trust risk category next to a many-source, high-trust
  identity is a normal shape, not a bug — vendors flag exposure the registry
  doesn't.  When you need to decide "how much of this verdict do I trust",
  read `source_count` and `max_trust_weight`, not `confidence` alone.
</Note>

## Errors

Same envelope as [POST /v2/check-address](/api-reference/v2-check-address).
Notable codes:

| HTTP | code                   | Why                                                                                                     |
| ---- | ---------------------- | ------------------------------------------------------------------------------------------------------- |
| 400  | `bad_request`          | empty address / unknown network                                                                         |
| 400  | `unsupported_network`  | `network` not in Aegis ingestion footprint (currently BSC / ETH / TRON).  Body has `supported_networks` |
| 401  | `missing_api_key`      | no `Authorization: Bearer …`                                                                            |
| 401  | `invalid_api_key`      | unknown / revoked                                                                                       |
| 402  | `insufficient_funds`   | USD balance too low; body has a `billing` envelope with the shortfall                                   |
| 409  | `idempotency_conflict` | same `Idempotency-Key`, different body                                                                  |
| 502  | `backend_unavailable`  | Supabase reachability failed.  **Charge refunded.**                                                     |

## Pricing vs x402 `/screen`

This endpoint and [`x402 /screen`](/endpoints/screen) return the same
data — same SQL queries, same `labels[]` shape, same risk fields.
They differ only in the commercial rail:

|                | V2 `/v2/screen`                                 | x402 `/screen`                                                         |
| -------------- | ----------------------------------------------- | ---------------------------------------------------------------------- |
| **Audience**   | B2B partners (wallets, exchanges)               | AI agents, anonymous                                                   |
| **Settlement** | USD balance debited per call (off-chain ledger) | USDC on Base, settled per call (`$0.10` floor — gas + facilitator fee) |
| **Onboarding** | Generate `aeg_…` key in your kabinet            | Sign EIP-3009 transferAuthorization                                    |
| **Auth**       | `Authorization: Bearer aeg_…`                   | None — payment IS the auth                                             |

If you're a wallet putting this behind a "send to address" prompt
for thousands of end-users, V2 is the right channel — same data,
no on-chain settlement step on each call.  Talk to sales for volume
pricing.

## See also

* [V2 introduction](/api-reference/v2-introduction)
* [POST /v2/check-address](/api-reference/v2-check-address) — full
  Aegis 4-tier verdict
* [GET /screen/{chain}/{address}](/endpoints/screen) — the x402
  counterpart of this endpoint


## OpenAPI

````yaml POST /screen
openapi: 3.1.0
info:
  description: >-
    Public, subscription-billed AML API. Send `Authorization: Bearer aeg_<key>`
    on every call.  See the user kabinet at
    https://app.aegis-kyt.com/account?tab=api to generate a key.
  title: Aegis Public API
  version: 2.0.0
servers:
  - description: Production
    url: https://api.aegis-kyt.com/v2
security: []
paths:
  /screen:
    post:
      tags:
        - v2-public
      summary: Cheap labels + consensus risk (Tier 0+1+2)
      description: >-
        Returns per-source labels and aggregated consensus risk in one call. 
        Stops after Aegis Tier 0+1+2 (SDN lookup + consensus view) — no 1-hop
        graph traversal, no BFS.  Billing is per your plan / commercial
        agreement.


        Designed for high-volume B2B integrations (wallet apps, exchanges)
        running a pre-send screen on every user-typed address.  For the full
        4-tier verdict use `/v2/check-address`.


        Send `Idempotency-Key: <token>` header to make retries safe — replays
        within 24h return the cached response without re-charging.
      operationId: check_address_light_screen_post
      parameters:
        - in: header
          name: Idempotency-Key
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: Idempotency-Key
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckAddressLightRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                additionalProperties: true
                title: Response Check Address Light Screen Post
                type: object
          description: Successful Response
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
        - ApiKeyBearer: []
components:
  schemas:
    CheckAddressLightRequest:
      properties:
        address:
          description: >-
            On-chain wallet.  EVM is lowercased internally; TRON/BTC/SOL
            preserved.
          examples:
            - TScSLnUodZVsgoGchZspDoimDjDB9bwqVv
            - '0x21a31ee1afc51d94c2efccaa2092ad1028285549'
          maxLength: 120
          minLength: 1
          title: Address
          type: string
        network:
          description: Chain identifier.  See `/v2/networks` for allowed values.
          examples:
            - TRON
            - ETH
          maxLength: 20
          minLength: 1
          title: Network
          type: string
      required:
        - address
        - network
      title: CheckAddressLightRequest
      type: object
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          title: Detail
          type: array
      title: HTTPValidationError
      type: object
    ValidationError:
      properties:
        ctx:
          title: Context
          type: object
        input:
          title: Input
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          title: Location
          type: array
        msg:
          title: Message
          type: string
        type:
          title: Error Type
          type: string
      required:
        - loc
        - msg
        - type
      title: ValidationError
      type: object
  securitySchemes:
    ApiKeyBearer:
      description: Your `aeg_…` API key from the dashboard (Account → API tab).
      scheme: bearer
      type: http

````