{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ugp.dev/2026-06-25/schemas/giving/donations.json",
  "name": "dev.ugp.giving.donations",
  "title": "Giving Donations",
  "description": "Schemas for the donations capability: submitting batches of donations, receiving per-platform bank payment instructions, advancing batch payment state, and reconciling settled funds. Money moves over bank rails (ACH, RTP, FedNow, wire) rather than through UCP payment-handler tokenization.",
  "$defs": {
    "batch_status": {
      "type": "string",
      "description": "Lifecycle state of a donation batch. The platform owns transitions up to funds leaving its bank (`created` -> `payment_initiated` -> `in_transit`); the giving service owns `settled`, `reconciled`, and `failed`. `canceled` is terminal for batches that never funded.",
      "enum": [
        "created",
        "payment_initiated",
        "in_transit",
        "settled",
        "reconciled",
        "canceled",
        "failed"
      ]
    },
    "payment_address": {
      "type": "object",
      "description": "Bank destination the platform pays into to fund a batch. With `address_scope: per_platform`, each platform receives a distinct destination account so that an incoming deposit self-identifies its originating platform by destination account number.",
      "required": [
        "account_number",
        "routing_number",
        "account_type",
        "supported_rails",
        "payment_reference"
      ],
      "properties": {
        "account_number": {
          "type": "string",
          "description": "Destination bank account number the platform sends funds to."
        },
        "routing_number": {
          "type": "string",
          "pattern": "^\\d{9}$",
          "description": "9-digit ABA routing number of the destination account."
        },
        "account_type": {
          "type": "string",
          "enum": [
            "checking",
            "savings"
          ],
          "description": "Type of the destination bank account."
        },
        "beneficiary_name": {
          "type": "string",
          "description": "Name on the destination account (the beneficiary of the funds)."
        },
        "supported_rails": {
          "type": "array",
          "description": "Bank payment rails this destination account can receive funds over.",
          "minItems": 1,
          "items": {
            "type": "string",
            "enum": [
              "ach",
              "rtp",
              "fednow",
              "wire"
            ]
          }
        },
        "wire_details": {
          "type": "object",
          "description": "Additional details required to send a wire to this account.",
          "properties": {
            "swift_bic": {
              "type": "string",
              "description": "SWIFT/BIC code of the beneficiary bank."
            },
            "bank_name": {
              "type": "string",
              "description": "Name of the beneficiary bank."
            },
            "bank_address": {
              "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/postal_address.json",
              "description": "Postal address of the beneficiary bank."
            }
          },
          "additionalProperties": true
        },
        "payment_reference": {
          "type": "string",
          "description": "Reference the platform MUST include with the payment so the deposit can be matched to the batch. Equals the `batch_id`."
        }
      },
      "additionalProperties": true
    },
    "create_batch_request": {
      "type": "object",
      "description": "Request body to create a donation batch. The batch groups donations the platform will remit to the nonprofit in a single bank transfer.",
      "required": [
        "donations"
      ],
      "properties": {
        "external_batch_id": {
          "type": "string",
          "description": "Platform's stable identifier for this batch. Idempotency key: resubmitting with the same `external_batch_id` MUST return the existing batch rather than creating a duplicate."
        },
        "donations": {
          "type": "array",
          "description": "Donations included in this batch.",
          "minItems": 1,
          "items": {
            "$ref": "https://ugp.dev/2026-06-25/schemas/giving/types/donation.json"
          }
        },
        "expected_total": {
          "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/amount.json",
          "description": "Platform-computed total of all donation amounts in minor units. The service validates this against the sum of accepted donations."
        },
        "currency": {
          "type": "string",
          "description": "ISO 4217 currency code for the batch total (e.g. \"USD\")."
        },
        "context": {
          "type": "object",
          "description": "Opaque platform context echoed back on the batch (e.g. internal references).",
          "additionalProperties": true
        }
      },
      "additionalProperties": true
    },
    "batch_response": {
      "type": "object",
      "description": "Representation of a donation batch returned on creation and retrieval. Includes the per-platform payment address the platform funds the batch into.",
      "required": [
        "ucp",
        "batch_id",
        "status",
        "total_amount",
        "currency",
        "donation_count",
        "payment_address"
      ],
      "properties": {
        "ucp": {
          "$ref": "https://ugp.dev/2026-06-25/schemas/ucp.json#/$defs/base",
          "description": "UCP protocol metadata for this response."
        },
        "batch_id": {
          "type": "string",
          "description": "Service-assigned identifier for the batch. Also used as the `payment_reference`."
        },
        "external_batch_id": {
          "type": "string",
          "description": "The platform's idempotency key for this batch, echoed back."
        },
        "status": {
          "$ref": "#/$defs/batch_status",
          "description": "Current lifecycle state of the batch."
        },
        "total_amount": {
          "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/amount.json",
          "description": "Total of all accepted donation amounts in minor units."
        },
        "currency": {
          "type": "string",
          "description": "ISO 4217 currency code for the batch total."
        },
        "donation_count": {
          "type": "integer",
          "description": "Number of accepted donations in the batch."
        },
        "payment_address": {
          "$ref": "#/$defs/payment_address",
          "description": "Bank destination the platform funds this batch into."
        },
        "donations": {
          "type": "array",
          "description": "Per-donation acceptance results.",
          "items": {
            "type": "object",
            "required": [
              "external_id",
              "accepted"
            ],
            "properties": {
              "external_id": {
                "type": "string",
                "description": "The platform's `external_id` for the donation."
              },
              "donation_id": {
                "type": "string",
                "description": "Service-assigned identifier for the accepted donation."
              },
              "accepted": {
                "type": "boolean",
                "description": "Whether the donation was accepted into the batch."
              },
              "reason": {
                "type": "string",
                "description": "Explanation when a donation was not accepted."
              }
            },
            "additionalProperties": true
          }
        },
        "expires_at": {
          "type": "string",
          "format": "date-time",
          "description": "Time by which the platform must fund the batch before the payment instructions expire."
        },
        "messages": {
          "type": "array",
          "description": "Informational, warning, or error messages about the batch.",
          "items": {
            "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/message.json"
          }
        }
      },
      "additionalProperties": true
    },
    "status_update_request": {
      "type": "object",
      "description": "Request body to advance a batch's payment state. The platform reports that it has initiated, sent, or canceled the funding payment.",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "payment_initiated",
            "in_transit",
            "canceled"
          ],
          "description": "Target state. The platform may only drive transitions up to funds leaving its bank."
        },
        "rail": {
          "type": "string",
          "enum": [
            "ach",
            "rtp",
            "fednow",
            "wire"
          ],
          "description": "Bank rail used to fund the batch."
        },
        "payment_trace": {
          "type": "object",
          "description": "Bank payment tracing details that help the service reconcile the incoming deposit.",
          "properties": {
            "trace_number": {
              "type": "string",
              "description": "Bank trace/reference number for the outbound payment."
            },
            "originator_name": {
              "type": "string",
              "description": "Name on the originating (platform) account."
            },
            "amount": {
              "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/amount.json",
              "description": "Amount of the payment in minor units."
            },
            "expected_settlement_date": {
              "type": "string",
              "format": "date",
              "description": "Date the platform expects the payment to settle."
            }
          },
          "additionalProperties": true
        },
        "reason": {
          "type": "string",
          "description": "Reason for the transition, required for `canceled`."
        }
      },
      "additionalProperties": true
    },
    "batch_state_response": {
      "title": "Batch State Response",
      "description": "Full batch state including payment tracing and reconciliation results. Returned when retrieving a batch or after a status update.",
      "allOf": [
        {
          "$ref": "#/$defs/batch_response"
        },
        {
          "type": "object",
          "properties": {
            "payment_trace": {
              "$ref": "#/$defs/status_update_request/properties/payment_trace",
              "description": "Bank payment tracing details reported by the platform."
            },
            "reconciliation": {
              "type": "object",
              "description": "Result of matching the settled deposit against the batch.",
              "properties": {
                "deposit_matched": {
                  "type": "boolean",
                  "description": "Whether an incoming deposit was matched to this batch."
                },
                "deposited_amount": {
                  "$ref": "https://ugp.dev/2026-06-25/schemas/common/types/amount.json",
                  "description": "Amount actually deposited in minor units."
                },
                "deposited_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Time the deposit was received."
                },
                "discrepancy": {
                  "type": "string",
                  "enum": [
                    "none",
                    "amount_mismatch",
                    "unmatched_deposit",
                    "partial"
                  ],
                  "description": "Nature of any discrepancy found during reconciliation."
                }
              },
              "additionalProperties": true
            }
          }
        }
      ]
    }
  },
  "version": "2026-06-25"
}
