Skip to content

feat: structured constraints for instruments and beyond#424

Draft
raginpirate wants to merge 1 commit intomainfrom
proto/funding-source-and-credential-constraints
Draft

feat: structured constraints for instruments and beyond#424
raginpirate wants to merge 1 commit intomainfrom
proto/funding-source-and-credential-constraints

Conversation

@raginpirate
Copy link
Copy Markdown
Contributor

@raginpirate raginpirate commented May 8, 2026

Prototype revision related to #288
This is heavily AI generated to quickly show the thinking and primitives; do not trust the descriptions or small implementation quirks here!

What

Introduces a single constraint primitive (constraint.json) and applies it consistently across instrument and credential availability. Replaces ad-hoc booleans (requires_card_verification,
billing_address_granularity) with a uniform shape: required_fields[] plus domain-specific custom keys.

New primitives

  • constraint.json — universal base: required_fields[] of property names + open additionalProperties for domain keys. Every constraint object in UCP follows this shape.
  • payment_funding_source.json — intermediate credential schema. Concrete funding-source credentials (card_credential, network_token_credential) inherit from it; consumers detect funding sources by ancestry, not
    annotation.
  • address_constraint.json — constraint-shaped, required_fields scoped to postal_address.json properties. Reusable across payments and fulfillment.
  • credential_constraint.json — { type, constraints } entry. Single primitive used on both axes below.

Reshaped

  • Card credentials split by verification scheme, not by PAN flavor.
    • card_credential.json carries cvc. Used whenever the verification is a CVC, regardless of whether number is an FPAN, network token, or wallet token.
    • network_token_credential.json (new) carries cryptogram + eci_value as schema-required. Used whenever the verification is cryptographic.
    • The card_number_type discriminator goes away — verification fields define the type.
  • available_card_payment_instrument.constraints exposes four top-level keys:
    • required_fields — names instrument properties that MUST be present (e.g. billing_address).
    • brands — accepted card brands (instrument-level; brand isn't a credential field).
    • billing_address — address_constraint describing what address fields must be populated.
    • credentials[] / funding_sources[] — same credential_constraint primitive on two orthogonal axes. credentials constrains the wire shape the handler ingests; funding_sources constrains the underlying instrument
      behind the wire credential. Constraints sit on the semantically correct axis only — never duplicated.

Cross-domain reuse

fulfillment_available_method.json adopts the same primitives — top-level constraints extending constraint.json, with destination reusing address_constraint.json. Closes the address-constraint gap on the
fulfillment side without inventing parallel concepts.

Example

  {
    "type": "card",
    "constraints": {
      "required_fields": ["billing_address"],
      "brands": ["visa", "mastercard"],
      "billing_address": {
        "required_fields": ["postal_code", "address_country"]
      },
      "credentials": [
        { "type": "token", "constraints": { "token_provider": ["dev.shopify.spt"] } }
      ],
      "funding_sources": [
        { "type": "card",          "constraints": { "required_fields": ["cvc"] } },
        { "type": "network_token" }
      ]
    }
  }

Reads as: handler accepts a token credential on the wire, conveying either a CVC-verified card or a cryptogram-verified network token. Merchant requires CVC on raw cards, requires a billing address with at least
postal code + country, and accepts visa/mastercard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant