Module adcp.types.domains.trusted_match.provider_registration

Classes

class Country (value: Any = <object object>, *, root: Any = <object object>)
Expand source code
class Country(ScalarStr):
    __slots__ = ()
    _constraints = {'pattern': '^[A-Z]{2}$'}

A str generated from a JSON Schema string root.

Ancestors

  • adcp.types._scalar.ScalarStr
  • adcp.types._scalar._ScalarRoot
  • builtins.str
class Status (*args, **kwds)
Expand source code
class Status(StrEnum):
    active = 'active'
    inactive = 'inactive'
    draining = 'draining'

Enum where members are also (and must be) strings

Ancestors

  • enum.StrEnum
  • builtins.str
  • enum.ReprEnum
  • enum.Enum

Class variables

var active
var draining
var inactive
class TmpProviderRegistration1 (**data: Any)
Expand source code
class TmpProviderRegistration1(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    provider_id: Annotated[
        str,
        Field(
            description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, as the key in `signals_by_provider` on Context Match responses and `targeting_kv_mapping` in publisher configuration, and as the key in `tmpx_providers` on Identity Match responses and `tmpx_macro_mapping` in publisher configuration. Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting. See publisher-targeting-kv-config.json and publisher-tmpx-config.json.",
            max_length=64,
            min_length=1,
            pattern='^[A-Za-z0-9_]+$',
        ),
    ]
    endpoint: Annotated[
        AnyUrl,
        Field(
            description='Base URL the router calls. The router appends /context for Context Match and /identity for Identity Match. MUST be HTTPS in production, validated against the canonical reserved IPv4 and IPv6 ranges, with the TCP connection pinned to the validated IP (DNS re-resolution alone is insufficient against rebinding). Publishers comparing two provider registrations for the same `endpoint` MUST canonicalize both per the AdCP URL canonicalization rules; two registrations differing only in case, default port, or path-slash collapsing are the same provider. See docs/trusted-match/specification#provider-registration-security, docs/building/implementation/security#webhook-url-validation-ssrf, and docs/reference/url-canonicalization.'
        ),
    ]
    context_match: Annotated[
        Literal[True], Field(description='Provider handles Context Match requests (POST /context).')
    ]
    identity_match: Annotated[
        StrictBool | None,
        Field(description='Provider handles Identity Match requests (POST /identity).'),
    ] = None
    countries: Annotated[
        list[Country] | None,
        Field(
            description="ISO 3166-1 alpha-2 country codes this provider serves. The router filters Identity Match providers by the request's country field. MUST be present and non-empty when identity_match is true.",
            min_length=1,
        ),
    ] = None
    uid_types: Annotated[
        list[uid_type.UidType] | None,
        Field(
            description="Identity types this provider can resolve. The router selects Identity Match providers whose uid_types overlaps with any uid_type in the request's identities array. MUST be present and non-empty when identity_match is true.",
            min_length=1,
        ),
    ] = None
    properties: Annotated[
        list[UUID] | None,
        Field(
            description='Property RIDs (UUID v7) this provider serves. When present, the router only sends requests from these properties to this provider. When absent, the provider serves all properties.',
            min_length=1,
        ),
    ] = None
    timeout_ms: Annotated[
        SchemaInt | None,
        Field(
            description="Per-provider timeout in milliseconds. The router skips this provider if it does not respond within this budget. Must be less than or equal to the router's overall latency_budget_ms. The router may further reduce this based on adaptive timeout allocation.",
            ge=5,
            le=5000,
        ),
    ] = 50
    priority: Annotated[
        SchemaInt | None,
        Field(
            description='Provider ordering for Context Match offer conflict resolution. Lower values have higher priority. When two providers return offers for the same package_id (a configuration error), the router keeps the offer from the higher-priority provider; equal priorities are broken by first response received. Identity Match eligibility remains a responder-scoped union because silent omission is not a negative vote. Also used for adaptive timeout allocation — higher-priority providers receive a larger share of the latency budget.',
            ge=0,
        ),
    ] = 0
    tmpx_slots: Annotated[
        list[TmpxSlot] | None,
        Field(
            description='Stable provider-local slot identifiers for the ordered TMPX chunks this provider mints. Slot IDs are opaque provider-namespaced tokens (e.g. `["primary","secondary"]`), NOT ad-server macro names — publishers map `(provider_id, slot_id)` → local destination via `tmpx_macro_mapping` in publisher-tmpx-config.json, so the destination namespace stays publisher-owned and the router never accepts a destination name from an untrusted provider. Distinct providers MAY reuse the same slot_id without collision because publisher lookup is keyed on `(provider_id, slot_id)`. Publishers use this list at startup to validate `tmpx_macro_mapping` covers every slot the provider mints and to detect config drift when the provider\'s slot contract changes. Ordering carries the ordered-prefix invariant: a provider that emits fewer chunks than it registered MUST emit an ordered prefix of this list — chunks map to slots in registration order and MUST NOT be shifted, sparse, or reordered. Cap of 2 slots in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. A provider that emits TMPX (populates `tmpx_chunks` on its identity-match response) MUST register this list; a provider that does not emit TMPX omits it. Schema cannot enforce that predicate because "emits TMPX" is not schema-visible.',
            max_length=2,
            min_length=1,
        ),
    ] = None
    status: Annotated[
        Status | None,
        Field(
            description='Provider lifecycle status. Active providers receive requests. Inactive providers are skipped entirely. Draining providers stop receiving new requests but in-flight requests complete normally.'
        ),
    ] = Status.active


    @field_validator('endpoint')
    @classmethod
    def _require_https_endpoint(cls, value: AnyUrl) -> AnyUrl:
        if value.scheme != 'https':
            raise ValueError('endpoint must use https')
        return value

    @model_validator(mode='after')
    def _require_identity_match_dimensions(self) -> TmpProviderRegistration1:
        if self.identity_match is True:
            if not self.countries:
                raise ValueError('countries is required when identity_match is true')
            if not self.uid_types:
                raise ValueError('uid_types is required when identity_match is true')
        return self

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var context_match : Literal[True]
var countries : list[Country] | None
var endpoint : pydantic.networks.AnyUrl
var identity_match : bool | None
var model_config
var priority : int | None
var properties : list[uuid.UUID] | None
var provider_id : str
var status : Status | None
var timeout_ms : int | None
var tmpx_slots : list[TmpxSlot] | None
var uid_types : list[UidType] | None

Inherited members

class TmpProviderRegistration2 (**data: Any)
Expand source code
class TmpProviderRegistration2(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    provider_id: Annotated[
        str,
        Field(
            description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, as the key in `signals_by_provider` on Context Match responses and `targeting_kv_mapping` in publisher configuration, and as the key in `tmpx_providers` on Identity Match responses and `tmpx_macro_mapping` in publisher configuration. Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting. See publisher-targeting-kv-config.json and publisher-tmpx-config.json.",
            max_length=64,
            min_length=1,
            pattern='^[A-Za-z0-9_]+$',
        ),
    ]
    endpoint: Annotated[
        AnyUrl,
        Field(
            description='Base URL the router calls. The router appends /context for Context Match and /identity for Identity Match. MUST be HTTPS in production, validated against the canonical reserved IPv4 and IPv6 ranges, with the TCP connection pinned to the validated IP (DNS re-resolution alone is insufficient against rebinding). Publishers comparing two provider registrations for the same `endpoint` MUST canonicalize both per the AdCP URL canonicalization rules; two registrations differing only in case, default port, or path-slash collapsing are the same provider. See docs/trusted-match/specification#provider-registration-security, docs/building/implementation/security#webhook-url-validation-ssrf, and docs/reference/url-canonicalization.'
        ),
    ]
    context_match: Annotated[
        StrictBool | None,
        Field(description='Provider handles Context Match requests (POST /context).'),
    ] = None
    identity_match: Annotated[
        Literal[True],
        Field(description='Provider handles Identity Match requests (POST /identity).'),
    ]
    countries: Annotated[
        list[Country] | None,
        Field(
            description="ISO 3166-1 alpha-2 country codes this provider serves. The router filters Identity Match providers by the request's country field. MUST be present and non-empty when identity_match is true.",
            min_length=1,
        ),
    ] = None
    uid_types: Annotated[
        list[uid_type.UidType] | None,
        Field(
            description="Identity types this provider can resolve. The router selects Identity Match providers whose uid_types overlaps with any uid_type in the request's identities array. MUST be present and non-empty when identity_match is true.",
            min_length=1,
        ),
    ] = None
    properties: Annotated[
        list[UUID] | None,
        Field(
            description='Property RIDs (UUID v7) this provider serves. When present, the router only sends requests from these properties to this provider. When absent, the provider serves all properties.',
            min_length=1,
        ),
    ] = None
    timeout_ms: Annotated[
        SchemaInt | None,
        Field(
            description="Per-provider timeout in milliseconds. The router skips this provider if it does not respond within this budget. Must be less than or equal to the router's overall latency_budget_ms. The router may further reduce this based on adaptive timeout allocation.",
            ge=5,
            le=5000,
        ),
    ] = 50
    priority: Annotated[
        SchemaInt | None,
        Field(
            description='Provider ordering for Context Match offer conflict resolution. Lower values have higher priority. When two providers return offers for the same package_id (a configuration error), the router keeps the offer from the higher-priority provider; equal priorities are broken by first response received. Identity Match eligibility remains a responder-scoped union because silent omission is not a negative vote. Also used for adaptive timeout allocation — higher-priority providers receive a larger share of the latency budget.',
            ge=0,
        ),
    ] = 0
    tmpx_slots: Annotated[
        list[TmpxSlot] | None,
        Field(
            description='Stable provider-local slot identifiers for the ordered TMPX chunks this provider mints. Slot IDs are opaque provider-namespaced tokens (e.g. `["primary","secondary"]`), NOT ad-server macro names — publishers map `(provider_id, slot_id)` → local destination via `tmpx_macro_mapping` in publisher-tmpx-config.json, so the destination namespace stays publisher-owned and the router never accepts a destination name from an untrusted provider. Distinct providers MAY reuse the same slot_id without collision because publisher lookup is keyed on `(provider_id, slot_id)`. Publishers use this list at startup to validate `tmpx_macro_mapping` covers every slot the provider mints and to detect config drift when the provider\'s slot contract changes. Ordering carries the ordered-prefix invariant: a provider that emits fewer chunks than it registered MUST emit an ordered prefix of this list — chunks map to slots in registration order and MUST NOT be shifted, sparse, or reordered. Cap of 2 slots in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. A provider that emits TMPX (populates `tmpx_chunks` on its identity-match response) MUST register this list; a provider that does not emit TMPX omits it. Schema cannot enforce that predicate because "emits TMPX" is not schema-visible.',
            max_length=2,
            min_length=1,
        ),
    ] = None
    status: Annotated[
        Status | None,
        Field(
            description='Provider lifecycle status. Active providers receive requests. Inactive providers are skipped entirely. Draining providers stop receiving new requests but in-flight requests complete normally.'
        ),
    ] = Status.active


    @field_validator('endpoint')
    @classmethod
    def _require_https_endpoint(cls, value: AnyUrl) -> AnyUrl:
        if value.scheme != 'https':
            raise ValueError('endpoint must use https')
        return value

    @model_validator(mode='after')
    def _require_identity_match_dimensions(self) -> TmpProviderRegistration2:
        if self.identity_match is True:
            if not self.countries:
                raise ValueError('countries is required when identity_match is true')
            if not self.uid_types:
                raise ValueError('uid_types is required when identity_match is true')
        return self

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var context_match : bool | None
var countries : list[Country] | None
var endpoint : pydantic.networks.AnyUrl
var identity_match : Literal[True]
var model_config
var priority : int | None
var properties : list[uuid.UUID] | None
var provider_id : str
var status : Status | None
var timeout_ms : int | None
var tmpx_slots : list[TmpxSlot] | None
var uid_types : list[UidType] | None

Inherited members

class TmpxMacro (value: Any = <object object>, *, root: Any = <object object>)
Expand source code
class TmpxMacro(ScalarStr):
    """Deprecated 3.1.8 registered macro-name compatibility model."""

    __slots__ = ()
    _constraints = {'max_length': 64, 'min_length': 1, 'pattern': '^[A-Z][A-Z0-9_]*$'}

Deprecated 3.1.8 registered macro-name compatibility model.

Ancestors

  • adcp.types._scalar.ScalarStr
  • adcp.types._scalar._ScalarRoot
  • builtins.str
class TmpxSlot (value: Any = <object object>, *, root: Any = <object object>)
Expand source code
class TmpxSlot(ScalarStr):
    __slots__ = ()
    _constraints = {'max_length': 64, 'min_length': 1, 'pattern': '^[a-zA-Z][a-zA-Z0-9_]*$'}

A str generated from a JSON Schema string root.

Ancestors

  • adcp.types._scalar.ScalarStr
  • adcp.types._scalar._ScalarRoot
  • builtins.str