|null */ public function connectionSchema(): ?array; /** * The Destination's own settings, including whatever selects the target * inside the remote system — the Mailchimp audience, the MailPoet lists. * * It takes the Connection because the options may come from the wire: * reading a provider's list of audiences at admin time is a read of its * SHAPE, never of a person's state, and it is what stops the merchant * pasting an audience id by hand (ADR 0007). * * @param array $credentials * @return array */ public function settingsSchema(array $credentials): array; /** Static prerequisites and field use; no Contact state or provider read. */ public function requirements(): DestinationRequirements; /** * Prove the credentials work, or throw. * * Throwing rather than returning a result mirrors * `IntegrationInterface::connect()`'s documented contract rather than * inventing a second convention for the same thing. * * @param array $credentials * @throws \RuntimeException */ public function testConnection(array $credentials): void; /** * Push one {@see PushSubject}. **This must be idempotent.** * * > Amended by ADR 0148: a webhook cannot be. A POST has no upsert, so it * > sends the subject's `deliveryId` — the same on every attempt — and the * > receiver dedupes on it. "Idempotent" means "safe to retry" there, with * > the receiver's help. * * That is contract and not an implementation note. A push is not one HTTP * call — some vendors need two or three — so a retry re-runs a sequence * that may already be half done, and no vendor offers an idempotency * header. Every implementation therefore keys on the vendor's own * email-keyed upsert, and running this twice for one subject must leave one * Contact (ADR 0008). * * Everything downstream stands on that clause: it is what makes retries * safe, what makes bulk re-push a support tool rather than a duplicate * generator, and what made a `wconvert_lead_deliveries` table buy * efficiency rather than correctness. * * **It takes a subject rather than a [[Lead]], and that is a decision * rather than a widening.** A merchant proving their credentials work sends * a test, and a test with a `Lead` in this signature would have to write a * row — a capture event that never happened, carrying a [[Consent Record]] * nobody was shown (ADR 0031). So what a type receives is the canonical * values and a flag saying where they came from; a type reads * `$subject->values` exactly as it used to read `CanonicalFields::of()`. */ public function push(PushSubject $subject, PushContext $context): PushResult; /** * Sustained jobs per minute this type can take. * * **There is no rate limiter in v1**, and this is what replaces one. * Organic capture cannot approach any vendor's limit; only bulk re-push * can, so {@see BulkRePush} staggers against this figure and immediate * dispatch stays immediate (ADR 0008). */ public function throughput(): int; }