Skip to content

DAFpay Payment Handler — com.dafpay

DAFpay is a payment handler: a "Pay with DAF" checkout method where a buyer settles a transaction by authorizing a grant from a donor-advised fund, much as Apple Pay or PayPal appear as wallet methods at checkout. It is declared as a com.dafpay entry in a UCP payment_handlers registry and is validated by source/schemas/payments/dafpay.json ($id: https://ugp.dev/schemas/payments/dafpay.json), whose config $def is carried as the handler entry's config. The DAF instruments the handler exposes are validated by the base payment_handler.json available_instruments field, which resolves to shopping/types/available_payment_instrument.json.

Relationship to UGP

UGP's donations capability moves money over bank rails — a platform remits funds it already holds to a bank destination, so UGP nonprofit profiles keep payment_handlers empty. DAFpay is the opposite case: a buyer who has not yet moved money chooses, at checkout, to pay from their DAF. That is exactly the UCP payment_handler primitive — a tokenized payment instrument processed at purchase time. DAFpay therefore lives under the Chariot-owned com.dafpay namespace as a UCP payment handler, not under dev.ugp.*, and is independent of the bank-rail donation-batch workflow described in Donations. A profile may advertise DAFpay alongside (or instead of) the giving capabilities.

Declaration

The handler is declared in a profile's payment_handlers registry, keyed by com.dafpay:

jsonc "payment_handlers": { "com.dafpay": [ { "version": "2026-06-25", "id": "dafpay-default", "spec": "https://ugp.dev/specification/dafpay", "schema": "https://ugp.dev/schemas/payments/dafpay.json", "available_instruments": [ { "instrument": "com.dafpay.daf", "display_name": "Pay with DAF" } ], "config": { "flow": "redirect", "authorization_url": "https://dafpay.com/authorize", "capture": "automatic", "settlement": { "mode": "guaranteed", "expected_clearing_days": 3 }, "supported_currencies": ["USD"], "fees": { "percentage": 0, "fixed": 0, "paid_by": "merchant" }, "available_instruments": [ { "instrument": "com.dafpay.daf", "display_name": "Pay with DAF", "min_amount": 5000, "supported_providers": ["Fidelity Charitable", "Schwab Charitable", "NPT"] } ] } } ] }

The complete example is available as example-dafpay-handler.json. Note available_instruments appears twice: at the handler level (required by the base payment-handler schema, minItems: 1) for coarse discovery, and inside config as the richly-typed DAFpay version carrying per-instrument constraints.

End-to-end flow

  1. Discover the handler. The buyer's platform fetches the merchant's /.well-known/ucp, reads payment_handlers["com.dafpay"], and renders a "Pay with DAF" button from available_instruments. Discovery is the only step that touches the UCP profile; the rest is the handler's own protocol.
  2. Authorize the grant. On click, the buyer is sent to authorization_url (for flow: "redirect") — or an embedded widget loads (flow: "embedded") — with the amount, currency, and the merchant return URL appended via return_url_param. The buyer selects a DAF sponsor and authorizes a grant.
  3. Capture. With capture: "automatic" the grant is captured on authorization; with manual the merchant captures it in a later call. A captured authorization yields a grant/transaction id the merchant records.
  4. Settle. DAF grants clear asynchronously. With settlement.mode: "guaranteed", DAFpay fronts the funds at authorization and the merchant is made whole immediately; with deferred, the merchant is paid when the grant clears (typically settlement.expected_clearing_days).
  5. Confirm. The buyer is returned to the merchant return URL with the authorization result; the merchant completes the order/receipt.

Settlement modes

authorize ──► capture ──► (guaranteed) merchant funded now ─────────────► clear └──► (deferred) merchant funded on clear ─────────► clear

  • guaranteed — DAFpay assumes the timing/clearing risk; the merchant sees funds at authorization. Best for checkout parity with cards/wallets.
  • deferred — the merchant is paid when the DAF sponsor disburses the grant, after roughly expected_clearing_days.

Config field reference

Field Type Notes
flow "redirect" | "embedded" Required. How the buyer authorizes the grant.
authorization_url URI Where the buyer authorizes the grant. Required for redirect.
return_url_param string Query param the merchant return URL is appended to. Default return_url.
capture "automatic" | "manual" When the grant is captured. Default automatic.
settlement.mode "guaranteed" | "deferred" Who bears clearing risk. Default guaranteed.
settlement.expected_clearing_days integer ≥ 0 Typical days for a grant to clear.
supported_currencies string[] (≥1) Required. ISO 4217 codes; USD today.
fees.percentage number ≥ 0 Percentage fee on the amount.
fees.fixed amount (minor units) Fixed per-transaction fee.
fees.paid_by "merchant" | "donor" Who bears the fee. Default merchant.
available_instruments[] daf_instrument[] (≥1) DAF instruments and per-instrument constraints.

daf_instrument

Field Type Notes
instrument "com.dafpay.daf" Required. The DAF instrument identifier.
display_name string Checkout button label. Default Pay with DAF.
supported_providers string[] DAF sponsors the grant can route to; omit for any.
min_amount / max_amount amount (minor units) Per-grant floor/ceiling.