Summary
PgTaskWebhookOutbox in 8.0.0-beta.8 accepts one fixed WebhookSender for the process. That is not sufficient for a multi-tenant seller whose request-scoped capabilities advertise tenant-specific RFC 9421 signing credentials.
This blocks adopting the SDK-managed durable outbox without either signing some tenant webhooks with the wrong key or collapsing all tenants onto one global signing identity.
Concrete adopter shape
Embedded Sales Agent serves multiple seller tenants through one PlatformRouter and one task registry. DecisioningPlatform.get_adcp_capabilities_for_request() resolves webhook_signing per tenant from that tenant active TenantSigningCredential. The existing delivery path loads the same tenant credential when producing the RFC 9421 signature.
The beta.8 outbox instead stores a single sender:
PgTaskWebhookOutbox(
pool=pool,
sender=WebhookSender.from_jwk(one_private_jwk),
...,
)
At worker time there is no request context from which the adopter can select the tenant credential. account_id is the buyer account identity and is not generically the seller tenant or signing scope. Buyer-supplied request_context is also not a trusted place for signing identity.
Using a subclass is intentionally unavailable: beta.8 correctly requires the exact PgTaskRegistry and PgTaskWebhookOutbox types so an override cannot invalidate the audited durability contract. The external-owner path would require duplicating the new atomic outbox just to vary key selection.
Required behavior
Please add an SDK-owned tenant-aware sender resolution path while retaining the exact audited registry/outbox types. For example:
- capture a trusted, adopter-resolved signing scope when the task is issued;
- store that scope in the encrypted/authenticated registration or outbox envelope;
- resolve a
WebhookSender from that scope for each delivery attempt;
- validate every resolved sender as RFC 9421-capable, SDK-owned IP-pinned transport with private destinations disabled;
- preserve byte-identical body/idempotency retries while allowing a fresh signature from the currently valid tenant key.
The signing scope must come from trusted server-side account/platform metadata, not push_notification_config, buyer context, or an unqualified buyer account ID.
A possible public shape is a concrete SDK resolver interface accepted by PgTaskWebhookOutbox, plus a handler hook that derives an opaque signing-scope ID from the resolved RequestContext. The fixed sender= path should remain the simple single-tenant default.
Acceptance criteria
- Two tenants handled by one registry/outbox can deliver with different
kid values matching their request-scoped advertised credentials.
- The trusted signing scope survives task issuance, process restart, terminal enqueue, and worker delivery.
- A buyer cannot select or alter the signing scope through request fields.
- Exact body and idempotency-key replay guarantees remain unchanged.
- Missing/invalid tenant sender resolution fails closed and leaves a recoverable/quarantined delivery record.
- Key rotation can select the currently valid tenant sender without rewriting the immutable webhook body.
Related context: #875 established the need for tenant-specific externally managed webhook signing capabilities. Beta.8 now provides the durable publisher, but only for a single fixed signing identity.
Summary
PgTaskWebhookOutboxin 8.0.0-beta.8 accepts one fixedWebhookSenderfor the process. That is not sufficient for a multi-tenant seller whose request-scoped capabilities advertise tenant-specific RFC 9421 signing credentials.This blocks adopting the SDK-managed durable outbox without either signing some tenant webhooks with the wrong key or collapsing all tenants onto one global signing identity.
Concrete adopter shape
Embedded Sales Agent serves multiple seller tenants through one
PlatformRouterand one task registry.DecisioningPlatform.get_adcp_capabilities_for_request()resolveswebhook_signingper tenant from that tenant activeTenantSigningCredential. The existing delivery path loads the same tenant credential when producing the RFC 9421 signature.The beta.8 outbox instead stores a single sender:
At worker time there is no request context from which the adopter can select the tenant credential.
account_idis the buyer account identity and is not generically the seller tenant or signing scope. Buyer-suppliedrequest_contextis also not a trusted place for signing identity.Using a subclass is intentionally unavailable: beta.8 correctly requires the exact
PgTaskRegistryandPgTaskWebhookOutboxtypes so an override cannot invalidate the audited durability contract. The external-owner path would require duplicating the new atomic outbox just to vary key selection.Required behavior
Please add an SDK-owned tenant-aware sender resolution path while retaining the exact audited registry/outbox types. For example:
WebhookSenderfrom that scope for each delivery attempt;The signing scope must come from trusted server-side account/platform metadata, not
push_notification_config, buyercontext, or an unqualified buyer account ID.A possible public shape is a concrete SDK resolver interface accepted by
PgTaskWebhookOutbox, plus a handler hook that derives an opaque signing-scope ID from the resolvedRequestContext. The fixedsender=path should remain the simple single-tenant default.Acceptance criteria
kidvalues matching their request-scoped advertised credentials.Related context: #875 established the need for tenant-specific externally managed webhook signing capabilities. Beta.8 now provides the durable publisher, but only for a single fixed signing identity.