Files
coordination-engine/spec/HybridmailPingenSpecification.md

1166 lines
39 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HybridmailPingenSpecification.md
## 1. Document Status
**Document:** HybridmailPingenSpecification.md
**Project:** hybridmail-connect
**Provider Flavor:** Pingen
**Parent Specification:** HybridmailAdapterSpecification.md
**Target Integration:** coordination-engine
**Adapter Contract:** AdapterInterfaceSpecification.md v1.0
**Status:** Draft v1.0
**Primary Scope:** Pingen-specific hybrid-mail provider flavor for letter upload, letter creation, validation, auto-send/manual-send control, Track & Trace, webhooks, return mail, delivered/undeliverable status mapping, and idempotent API usage.
## 2. Purpose
This document specifies the Pingen provider flavor for `hybridmail-connect`.
The Pingen flavor implements the generic hybrid-mail adapter model for the Pingen Letter API. It maps Pingens API concepts into the provider-neutral hybrid-mail model used by `coordination-engine`.
The purpose of this document is to capture:
* Pingen-specific provider capabilities.
* Pingen-specific workflow stages.
* Pingen letter, file, address, validation, send, status, Track & Trace, and webhook concepts.
* Pingen return-mail and undeliverable processing.
* Pingen delivery-confirmation semantics.
* Pingen idempotency and rate-limit behavior.
* Pingen evidence event mapping.
* Pingen-specific limitations and assumptions.
* Pingen-specific MVP boundaries.
The Pingen flavor MUST remain compatible with `HybridmailAdapterSpecification.md` and MUST NOT leak Pingen-specific terminology into the core coordination model except through mapped provider metadata.
## 3. Grounding Summary
The public Pingen material indicates the following relevant features:
* Pingen provides a Letter API for automated postal-letter sending.
* Pingen offers SDKs, including PHP, Python, Go, .NET, and code examples.
* API authentication uses OAuth-style client credentials in common tooling/examples.
* Pingen supports Idempotency-Key headers.
* Pingen supports rate limiting and configurable send limits.
* Pingen offers staging/sandbox or full-feature simulation.
* Pingen supports document validation.
* Pingen supports configurable address position.
* Pingen supports auto-send control.
* Pingen offers Track & Trace for real-time progress transparency.
* Pingen provides webhooks for status changes.
* Public webhook categories include letter issues, sent letters, undeliverable letters, and delivered letters.
* Pingen automates return-mail processing and can provide return details via email and webhook.
* Pingen distinguishes ordinary postal dispatch from actual delivery-confirmation products. Ordinary letters may not receive final post-office delivery confirmation.
These facts define the baseline for this provider flavor.
## 4. Provider Flavor Identity
```yaml
HybridmailProviderFlavorDescriptor:
provider_name: pingen
provider_label: Pingen Letter API
provider_family: hybridmail
adapter_contract_version: "1.0"
parent_specification: HybridmailAdapterSpecification.md
deployment_mode: external
```
## 5. Pingen Capability Descriptor
The Pingen flavor MUST expose a capability descriptor.
```yaml
HybridmailProviderFlavorDescriptor:
provider_name: pingen
provider_version: provider_specific
supported_file_types:
- pdf
supported_attachment_file_types:
- provider_specific
supports_single_letter: true
supports_bulk: true
supports_serial_letters: true
supports_attachments: provider_specific
supports_preview: true
supports_webhooks: true
supports_polling: true
supports_track_and_trace: true
supports_registered_mail: true
supports_delivery_confirmation: product_dependent
supports_return_mail: true
supports_address_correction: provider_specific
supports_international_mail: true
supports_cancellation: provider_specific
supports_staging: true
supports_full_feature_simulation: true
supports_idempotency: true
supports_rate_limits: true
supports_configurable_send_limits: true
supports_auto_send: true
supports_address_position_configuration: true
supports_document_validation: true
supported_print_options:
color_mode: provider_specific
simplex_duplex: provider_specific
envelope_selection: provider_specific
address_position: true
supported_postal_products:
- standard
- registered
- delivery_confirmation
- international
- provider_specific
limitations:
- Ordinary postal letters usually do not provide final post-office delivery confirmation.
- Delivered-letter webhook semantics must be interpreted according to selected product and Pingen status details.
- Return-mail information may arrive late.
- Public documentation confirms webhook categories, but exact event payload fields must be implemented against the live Pingen API documentation.
- Provider-native status names must be preserved in metadata and mapped conservatively.
```
## 6. Pingen-Specific Conceptual Workflow
The Pingen flavor uses a file/letter-centric workflow.
```text
authenticate
→ upload file / create letter
→ configure address position and sending options
→ validate letter
→ optionally auto-send or manually trigger send
→ Track & Trace status changes
→ webhook or polling status ingestion
→ sent-letter evidence
→ undeliverable/return-mail evidence where applicable
→ delivered-letter evidence where product/status supports it
```
The adapter MUST preserve this distinction:
```text
Letter creation is not sending.
Validation success is not postal dispatch.
Sent status is not necessarily final delivery.
Ordinary postal dispatch is not proof of human awareness.
Return-mail events may arrive late and can change the delivery assessment.
```
## 7. Pingen Object Mapping
## 7.1 Generic to Pingen Mapping
| Generic hybrid-mail concept | Pingen flavor concept |
| --------------------------- | --------------------------------------------------------------------------------------------- |
| `HybridmailLetter` | Pingen letter |
| `HybridmailDocumentRef` | Uploaded file / letter document |
| `HybridmailAttempt` | Pingen letter creation/send operation |
| `HybridmailBatch` | Bulk or serial letter group where used |
| `PostalRecipient` | Address extracted from document or configured via address position / metadata where supported |
| `HybridmailOptions` | Pingen send, print, address, and delivery options |
| `HybridmailPreview` | Pingen preview or validation representation where supported |
| `HybridmailTimeline` | Pingen Track & Trace and webhook timeline |
## 7.2 PingenLetter
```yaml
PingenLetter:
pingen_letter_id: string
hybridmail_letter_id: string?
coordination_case_id: string?
participant_id: string?
provider_status: string?
normalized_status: string
file_ref: ResourceRef
page_count: integer?
sheet_count: integer?
address_position: PingenAddressPosition?
options: PingenLetterOptions?
validation_result: PingenValidationResult?
track_and_trace_ref: string?
webhook_event_refs:
- string
created_at: timestamp
updated_at: timestamp?
metadata: object?
```
## 7.3 PingenFile
```yaml
PingenFile:
pingen_file_id: string?
hybridmail_letter_id: string?
original_file_ref: ResourceRef
file_type: pdf | unknown
file_size_bytes: integer?
integrity_hash: string?
upload_state: pending | uploaded | rejected | failed | unknown
created_at: timestamp
metadata: object?
```
## 7.4 PingenAttempt
```yaml
PingenAttempt:
pingen_attempt_id: string
hybridmail_letter_id: string
pingen_letter_id: string?
provider_operation_id: string?
idempotency_key: string
operation_type: create_letter | validate_letter | send_letter | cancel_letter | status_poll | webhook_ingest
state: pending | accepted | rejected | failed | completed | duplicate | unknown
created_at: timestamp
updated_at: timestamp?
raw_provider_response_ref: string?
```
## 7.5 PingenBatch
```yaml
PingenBatch:
pingen_batch_id: string?
hybridmail_batch_id: string
coordination_case_id: string?
batch_type: bulk | serial | campaign | mixed | unknown
letters:
- hybridmail_letter_id
state: pending | partial | completed | failed | unknown
created_at: timestamp
updated_at: timestamp?
```
Batch-level events MUST NOT be treated as success for every child letter unless Pingen provides per-letter status or policy explicitly accepts batch-level evidence.
## 8. Pingen Address Model
Pingen supports configurable address position. The Pingen flavor MUST model address positioning explicitly.
```yaml
PingenAddressPosition:
source: configured | detected | provider_default | unknown
position: left | right | provider_specific | unknown
page_number: integer?
bounding_box: object?
confidence: low | medium | high
```
Generic postal recipient mapping:
```yaml
PostalRecipient:
recipient_id: string?
name_lines:
- string
organization: string?
street: string?
house_number: string?
address_addition: string?
postal_code: string?
city: string?
region: string?
country_code: string?
country_name: string?
address_source: extracted_from_document | provided_metadata | provider_detected | manual | unknown
address_quality: PostalAddressQuality?
```
If Pingen validation detects address issues, they MUST be mapped into `PingenValidationIssue` and then into generic `HybridmailValidationIssue`.
## 9. Pingen Validation Model
Pingen validation results MUST be mapped into generic `HybridmailValidationResult`.
```yaml
PingenValidationResult:
pingen_letter_id: string
provider_validation_state: string?
validation_state: pending | passed | action_required | failed | unknown
issues:
- PingenValidationIssue
validated_at: timestamp?
raw_provider_response_ref: string?
```
```yaml
PingenValidationIssue:
provider_issue_code: string?
issue_code: string
severity: info | warning | action_required | fatal
category: format | page_size | pdf | address | address_position | restricted_area | margins | file_size | page_count | postage | country | provider_policy | unknown
message: string
page_number: integer?
bounding_box: object?
fixable: boolean?
```
## 10. Pingen Validation Issue Mapping
| Pingen validation concern | Generic validation category | Normalized issue code |
| --------------------------------- | --------------------------- | ------------------------------- |
| Invalid PDF | `pdf` / `format` | `invalid_pdf` |
| Unsupported file type | `format` | `unsupported_file_type` |
| Address not found or unreadable | `address` | `address_not_detected` |
| Address position invalid | `address_position` | `address_position_invalid` |
| Address format invalid | `address` | `address_format_invalid` |
| Unsupported destination country | `country` | `unsupported_country` |
| Page or file constraints violated | `page_count` / `file_size` | `document_constraint_violation` |
| Postal product invalid | `postage` | `unsupported_product` |
| Provider policy rejection | `provider_policy` | `provider_policy_rejected` |
| Unknown validation issue | `unknown` | `unknown_validation_issue` |
Validation failure MUST emit:
```text
payload.validation_failed
```
Validation success MUST emit:
```text
payload.validation_passed
```
If Pingen classifies an issue as fixable/action-required, the adapter SHOULD include severity `action_required` rather than immediately treating the coordination case as permanently failed.
## 11. Pingen Letter Options
The Pingen flavor MUST map Pingen options into the generic `HybridmailOptions`.
```yaml
PingenLetterOptions:
color_mode: color | grayscale | provider_default | unknown
print_sides: simplex | duplex | provider_default | unknown
address_position: left | right | provider_default | unknown
postage_product: standard | registered | delivery_confirmation | international | provider_specific
country_scope: domestic | international | unknown
auto_send: boolean?
dispatch_mode: manual_review | auto_send | submit_later | scheduled
desired_dispatch_date: date?
return_mail_handling: none | provider_processed | scan_return | digital_return_info | physical_return | unknown
delivery_confirmation_requested: boolean?
metadata: object?
```
Provider-native option names MUST be preserved in metadata.
The adapter MUST NOT assume support for a postal product unless the Pingen capability descriptor confirms it.
## 12. Pingen Auto-Send Handling
Pingen supports auto-send behavior according to public API materials.
The adapter MUST explicitly model auto-send, because it affects the transition from creation/validation to physical dispatch.
```yaml
PingenAutoSendPolicy:
auto_send: boolean
send_after_validation: boolean?
require_adapter_approval: boolean?
require_coordination_policy_approval: boolean?
```
Recommended safety rule:
```text
For high-assurance or expensive physical-mail scenarios,
auto_send SHOULD default to false unless explicitly enabled by policy.
```
If `auto_send=true`, the adapter MUST make duplicate-send prevention especially strict.
## 13. Pingen Track & Trace Model
Pingen provides Track & Trace progress updates. The adapter MUST represent those as a timeline.
```yaml
PingenTrackAndTraceEvent:
event_id: string
pingen_letter_id: string
provider_status: string
normalized_status: string
event_category: letter_issue | sent_letter | undeliverable_letter | delivered_letter | return_mail | processing | unknown
occurred_at: timestamp?
observed_at: timestamp
raw_provider_response_ref: string?
metadata: object?
```
Track & Trace events should map to the strongest safe generic event.
If the event only indicates process progress, it MUST NOT be mapped to postal delivery confirmation.
## 14. Pingen Webhook Model
Pingen public help identifies webhook categories:
```text
Letter issues
Sent letters
Undeliverable letters
Delivered letters
```
The adapter MUST support these categories where available.
```yaml
PingenWebhookEvent:
pingen_webhook_event_id: string
webhook_category: letter_issue | sent_letter | undeliverable_letter | delivered_letter | unknown
pingen_letter_id: string?
provider_event_id: string?
occurred_at: timestamp?
observed_at: timestamp
raw_payload_ref: string?
normalized_events:
- EvidenceEvent
```
## 15. Pingen Webhook Category Mapping
| Pingen webhook category | Generic event | Evidence interpretation |
| ----------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Letter issues | `payload.validation_failed` or `delivery.payload.rejected` | Strong issue/failure/action-required evidence depending payload |
| Sent letters | `delivery.postal.handed_over` or `delivery.payload.submitted` | Strong dispatch evidence only if semantics confirm physical send/handover |
| Undeliverable letters | `delivery.postal.undeliverable` or `delivery.postal.return_received` | Strong negative delivery evidence |
| Delivered letters | `delivery.postal.delivery_confirmed` | Strong delivery evidence if product/status supports delivery confirmation |
Important:
```text
A "sent letters" event should not be interpreted as "recipient received the letter".
A "delivered letters" event must be interpreted according to the postal product and provider semantics.
```
## 16. Pingen Return Mail Model
Pingen supports automated return-mail processing and provides return details via channels including webhooks.
```yaml
PingenReturnEvent:
return_event_id: string
pingen_letter_id: string
provider_return_id: string?
return_type: undeliverable | address_unknown | recipient_moved | refused | insufficient_address | other | unknown
return_details: string?
address_correction: PostalRecipient?
return_document_ref: ResourceRef?
occurred_at: timestamp?
observed_at: timestamp
raw_event_ref: string?
```
Return events usually create strong negative delivery evidence:
```text
delivery.postal.return_received
delivery.postal.undeliverable
```
Return events may arrive late and MUST be preserved even if the coordination case has already progressed.
## 17. Pingen Delivery Confirmation Model
Pingen delivery-confirmation evidence is product-dependent.
```yaml
PingenDeliveryConfirmation:
confirmation_id: string
pingen_letter_id: string
product_type: delivery_confirmation | registered | provider_specific
provider_status: string?
normalized_status: delivered | attempted | refused | undeliverable | returned | unknown
occurred_at: timestamp?
observed_at: timestamp
raw_event_ref: string?
```
The adapter MUST only emit:
```text
delivery.postal.delivery_confirmed
```
when the Pingen status and selected postal product semantically support delivery confirmation.
Ordinary letter dispatch MUST NOT be mapped to `delivery.postal.delivery_confirmed`.
## 18. Pingen Status Model
The Pingen flavor MUST preserve raw provider status and map it to normalized status.
```yaml
PingenStatusRecord:
status_record_id: string
pingen_letter_id: string
provider_status: string
normalized_status: string
status_scope: letter | validation | sending | track_and_trace | webhook | return_mail | unknown
observed_at: timestamp
raw_provider_response_ref: string?
```
## 19. Normalized Pingen Status Categories
The Pingen flavor SHOULD map native statuses into these normalized categories:
```text
letter.created
letter.uploaded
letter.validation_pending
letter.validation_passed
letter.validation_failed
letter.action_required
letter.ready_for_sending
letter.submitted_for_sending
letter.processing
letter.handed_to_postal_service
letter.sent
letter.delivery_confirmed
letter.undeliverable
letter.return_received
letter.cancelled
letter.failed
letter.status_unknown
```
Where Pingen status granularity is insufficient, the adapter MUST use the nearest weaker event and preserve the raw status in metadata.
## 20. Pingen-to-Generic Event Mapping
| Pingen workflow event | Generic event | Evidence interpretation |
| -------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------- |
| File/letter accepted | `delivery.payload.accepted` | Digital submission accepted |
| Letter rejected | `delivery.payload.rejected` | Attempt failed |
| Validation passed | `payload.validation_passed` | Provider-processable |
| Letter issue | `payload.validation_failed` or `delivery.payload.rejected` | Issue/action-required/failure |
| Ready for sending | `delivery.payload.available` | Operational readiness |
| Auto-send triggered | `delivery.payload.submitted` | Provider instructed to send |
| Manual send triggered | `delivery.payload.submitted` | Provider instructed to send |
| Processing | `delivery.production.started` | Provider processing began |
| Sent-letter event | `delivery.postal.handed_over` if semantics support; otherwise `delivery.payload.submitted` | Strong dispatch or send-process evidence |
| Delivered-letter event | `delivery.postal.delivery_confirmed` if product/status supports | Strong delivery evidence |
| Undeliverable-letter event | `delivery.postal.undeliverable` | Strong negative evidence |
| Return details received | `delivery.postal.return_received` | Strong negative evidence |
| Track & Trace update | status-specific mapped event | Preserve raw status |
| Cancellation | `delivery.payload.failed` or cancellation metadata | Attempt stopped |
## 21. Evidence Grading Rules
### 21.1 Pingen Letter Accepted
```yaml
event_type: delivery.payload.accepted
evidence_grade:
strength: weak
actor_certainty: none
authority_certainty: none
payload_certainty: medium
interaction_certainty: none
timing_certainty: medium
channel_certainty: medium
non_repudiation_strength: low
notes:
- Pingen accepted the letter or file into the API workflow.
- This does not prove validation, sending, postal handover, or delivery.
```
### 21.2 Pingen Validation Passed
```yaml
event_type: payload.validation_passed
evidence_grade:
strength: medium
actor_certainty: none
authority_certainty: none
payload_certainty: high
interaction_certainty: none
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Pingen validation passed.
- The letter can proceed to sending according to provider rules.
```
### 21.3 Pingen Letter Issue / Validation Failed
```yaml
event_type: payload.validation_failed
evidence_grade:
strength: negative
actor_certainty: none
authority_certainty: none
payload_certainty: high
interaction_certainty: none
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Pingen reported a letter issue or validation failure.
- The issue should be categorized and preserved.
```
### 21.4 Pingen Sent-Letter Event
```yaml
event_type: delivery.postal.handed_over
evidence_grade:
strength: strong
actor_certainty: none
authority_certainty: none
payload_certainty: high
interaction_certainty: none
timing_certainty: high
channel_certainty: high
non_repudiation_strength: medium
notes:
- Pingen reports the letter as sent or handed into the postal process.
- This is strong dispatch evidence.
- It does not prove that the recipient received or read the letter.
```
If the native status only means “submitted for sending” and not postal handover, the adapter MUST instead map to:
```text
delivery.payload.submitted
```
### 21.5 Pingen Delivered-Letter Event
```yaml
event_type: delivery.postal.delivery_confirmed
evidence_grade:
strength: strong
actor_certainty: low
authority_certainty: none
payload_certainty: high
interaction_certainty: low
timing_certainty: high
channel_certainty: high
non_repudiation_strength: medium
notes:
- Pingen reports delivered-letter evidence.
- This event is product- and status-dependent.
- It may still not prove that the intended human personally read the payload.
```
### 21.6 Pingen Undeliverable / Return Mail
```yaml
event_type: delivery.postal.return_received
evidence_grade:
strength: negative
actor_certainty: none
authority_certainty: none
payload_certainty: high
interaction_certainty: none
timing_certainty: high
channel_certainty: high
non_repudiation_strength: medium
notes:
- Pingen reports undeliverable or return-mail processing.
- This is strong negative evidence for the physical delivery attempt.
```
## 22. Pingen Evidence Assessment
The Pingen flavor SHOULD provide a Pingen-native evidence assessment.
```yaml
PingenEvidenceAssessment:
hybridmail_letter_id: string
pingen_letter_id: string?
participant_id: string?
category: success | fail | undef
subclass: string
confidence: low | medium | high
strongest_signal: string?
evidence_summary:
- string
recommended_coordination_interpretation: string?
```
### 22.1 Pingen Adapter Success Subclasses
```text
success.letter_created
success.validation_passed
success.ready_for_sending
success.submitted_for_sending
success.sent_letter
success.handed_to_postal_service
success.delivery_confirmed
success.return_info_processed
```
### 22.2 Pingen Adapter Fail Subclasses
```text
fail.upload_rejected
fail.validation_failed
fail.letter_issue
fail.address_position_invalid
fail.address_invalid
fail.unsupported_file_type
fail.unsupported_country
fail.product_invalid
fail.send_limit_exceeded
fail.provider_rejected
fail.cancelled
fail.undeliverable
fail.return_received
```
### 22.3 Pingen Adapter Undef Subclasses
```text
undef.pending
undef.uploaded_only
undef.validation_pending
undef.action_required
undef.ready_but_not_sent
undef.auto_send_pending
undef.submitted_for_sending
undef.processing
undef.sent_but_delivery_unproven
undef.handed_to_postal_service_but_delivery_unproven
undef.track_and_trace_pending
undef.return_mail_pending
undef.no_final_status_expected
undef.delivered_status_semantics_unclear
undef.conflicting_evidence
undef.channel_degraded
```
## 23. Pingen Workflow States
The Pingen flavor SHOULD support these normalized workflow states:
```text
created
upload_requested
uploaded
upload_failed
validation_pending
validation_passed
validation_failed
action_required
ready_for_sending
auto_send_pending
send_requested
submitted_for_sending
processing
sent
handed_to_postal_service
delivery_confirmed
undeliverable
return_received
cancelled
failed
unknown
```
These are Pingen-flavor states, not coordination result states.
## 24. Pingen Idempotency and Duplicate Send Prevention
Pingen publicly supports Idempotency-Key headers. The Pingen flavor MUST use them for externally visible create/send operations where supported.
The adapter MUST also maintain local idempotency records to prevent duplicate physical sends.
Idempotency scope SHOULD include:
```text
coordination_case_id
participant_id
delivery_id
payload_id
payload_integrity_hash
provider_flavor
postal recipient
letter options
auto_send flag
```
A repeated `delivery.submit_letter` request with the same idempotency key MUST NOT create a second physical send.
If the repeated request refers to a changed payload, address, auto-send setting, or delivery product, the adapter MUST reject it as an idempotency conflict unless a new idempotency key is provided.
## 25. Pingen Rate Limits and Send Limits
Pingen publicly advertises rate limiting and configurable send limits.
The adapter SHOULD model rate-limit and send-limit events.
```yaml
PingenLimitState:
provider_account_ref: string?
rate_limit_status: available | limited | exhausted | unknown
send_limit_status: available | limited | exhausted | unknown
reset_at: timestamp?
metadata: object?
```
Relevant events:
```text
system.provider.degraded
delivery.payload.rejected
```
If a send limit blocks dispatch, the adapter SHOULD classify the letter as:
```text
undef.pending
```
if retry/continuation is expected, or:
```text
fail.provider_rejected
```
if the provider rejects the request as final.
## 26. Pingen Webhook Handling
The Pingen flavor SHOULD prefer webhooks for status changes where available and use polling as a fallback.
Webhook handling MUST:
* verify authenticity where supported.
* deduplicate events.
* preserve raw payload references.
* map categories conservatively.
* accept late return-mail events.
* emit per-letter evidence events.
* avoid treating webhook delivery to the adapter as postal delivery to the recipient.
```yaml
PingenWebhookHandling:
enabled: boolean
verification_mode: signature | shared_secret | ip_allowlist | none | unknown
subscribed_categories:
- letter_issue
- sent_letter
- undeliverable_letter
- delivered_letter
fallback_polling_enabled: boolean
```
## 27. Pingen Status Polling
The Pingen flavor MUST support polling if the API exposes status retrieval.
```yaml
PingenStatusPollingConfig:
enabled: boolean
initial_delay_seconds: integer
interval_seconds: integer
max_duration_seconds: integer
terminal_statuses:
- delivered
- undeliverable
- returned
- failed
- cancelled
no_final_status_expected_after_seconds: integer?
```
Polling MUST preserve status history and MUST NOT overwrite raw evidence.
## 28. Pingen Raw Event Preservation
The Pingen flavor SHOULD preserve raw provider responses or references to them.
```yaml
RawPingenEventRef:
raw_event_id: string
source: api_response | status_poll | webhook | track_and_trace | validation | operator
endpoint: string?
storage_ref: string?
received_at: timestamp
redacted: boolean
```
Normalized events SHOULD reference raw Pingen event data where available.
## 29. Pingen Channel Health
```yaml
PingenChannelHealth:
provider_name: pingen
provider_account_ref: string?
status: healthy | degraded | failing | unknown
authentication_status: valid | expired | missing | insufficient | unknown
api_status: healthy | degraded | unavailable | unknown
upload_status: healthy | degraded | unavailable | unknown
validation_status: healthy | degraded | unavailable | unknown
track_and_trace_status: healthy | degraded | unavailable | unknown
webhook_status: healthy | degraded | unavailable | not_configured | unknown
rate_limit_status: available | limited | exhausted | unknown
send_limit_status: available | limited | exhausted | unknown
staging_status: healthy | degraded | unavailable | not_configured | unknown
known_degradations:
- string
```
Health events SHOULD map to:
```text
system.provider.degraded
system.provider.unavailable
system.adapter.health_changed
```
## 30. Security Requirements
The Pingen flavor MUST:
* protect Pingen API credentials.
* use secure transport.
* use provider Idempotency-Key support where available.
* maintain local idempotency records.
* avoid duplicate physical sends.
* verify webhooks where supported.
* avoid logging document contents.
* protect postal recipient data.
* protect return-mail details.
* separate staging/sandbox and production configuration.
* support tenant/account separation where applicable.
## 31. Privacy Requirements
The Pingen flavor SHOULD:
* store payload references instead of payload content where possible.
* support metadata-only mode after provider submission.
* mask postal address data in logs.
* support configurable retention of raw provider responses.
* support configurable retention of return-mail details.
* separate operational diagnostics from coordination evidence.
* document provider-side retention limitations.
* support deletion or anonymization workflows where legally possible.
## 32. Reliability Requirements
The Pingen flavor MUST support:
* idempotent create/send requests.
* duplicate webhook event detection.
* out-of-order status handling.
* polling-based status recovery.
* late return-mail events.
* late delivered-letter events.
* retryable upload failures.
* non-retryable validation failures.
* provider timeout handling.
* validation issue preservation.
* rate-limit handling.
* send-limit handling.
* Track & Trace history preservation.
* correlation preservation.
* dead-letter handling for unprocessable provider responses.
## 33. Minimal API Surface
The Pingen flavor SHOULD implement or expose these conceptual operations through `hybridmail-connect`.
### 33.1 Adapter Contract Operations
```text
GET /adapter/descriptor
GET /adapter/health
POST /adapter/actions
POST /adapter/events/provider
GET /adapter/events
GET /adapter/letters/{id}/timeline
GET /adapter/letters/{id}/assessment
```
### 33.2 Pingen Flavor Operations
```text
POST /pingen/letters
POST /pingen/letters/{id}/send
POST /pingen/letters/{id}/cancel
GET /pingen/letters/{id}
GET /pingen/letters/{id}/status
GET /pingen/letters/{id}/track-and-trace
GET /pingen/letters/{id}/return-info
GET /pingen/letters/{id}/delivery-confirmation
GET /pingen/letters/{id}/timeline
GET /pingen/letters/{id}/assessment
POST /pingen/webhooks
GET /pingen/channel-health
```
The exact provider endpoint names MUST be implemented according to the live Pingen API documentation. The conceptual operations above define the adapter-facing semantic model.
## 34. Example End-to-End Flow
### 34.1 Single Pingen Letter with Manual Send
1. `coordination-engine` creates a coordination case.
2. A PDF payload is registered.
3. Policy selects `hybridmail-connect` with provider flavor `pingen`.
4. `coordination-engine` sends `delivery.submit_letter`.
5. `hybridmail-connect` creates a Pingen letter with `auto_send=false`.
6. Pingen accepts the letter.
7. The adapter emits `delivery.payload.accepted`.
8. Pingen validates the letter.
9. If validation passes, the adapter emits `payload.validation_passed`.
10. Policy approves sending.
11. The adapter sends or submits the letter.
12. The adapter emits `delivery.payload.submitted`.
13. Pingen Track & Trace reports sent-letter progress.
14. The adapter emits `delivery.postal.handed_over` only if the native event semantics support physical dispatch/handover.
15. `coordination-engine` evaluates whether dispatch evidence is sufficient for the case policy.
### 34.2 Auto-Send Letter
1. `coordination-engine` submits a letter with `auto_send=true`.
2. The adapter validates idempotency and payload identity.
3. Pingen accepts the request.
4. Validation and send may proceed without separate manual approval.
5. The adapter emits distinct events for validation and send stages as they become observable.
6. If validation fails, the adapter emits `payload.validation_failed`.
7. If sending proceeds, the adapter emits `delivery.payload.submitted` and later stronger status events.
### 34.3 Pingen Letter Issue
1. Pingen reports a letter issue through webhook or status polling.
2. The adapter classifies the issue.
3. The adapter emits `payload.validation_failed` or `delivery.payload.rejected`.
4. `coordination-engine` marks the participant attempt as action-required or failed.
5. Policy requests correction, alternate document generation, or fallback.
### 34.4 Undeliverable / Return Mail
1. A letter was sent.
2. Pingen later reports it as undeliverable or return mail is processed.
3. The adapter emits `delivery.postal.undeliverable` or `delivery.postal.return_received`.
4. `coordination-engine` updates the participant delivery assessment.
5. Policy may trigger address correction, alternate channel, or manual review.
### 34.5 Delivered-Letter Product
1. A letter is sent using a delivery-confirmation-capable product.
2. Pingen reports delivered-letter evidence.
3. The adapter confirms the product/status semantics.
4. The adapter emits `delivery.postal.delivery_confirmed`.
5. `coordination-engine` evaluates whether this satisfies the intended result.
## 35. Pingen MVP Scope
The first Pingen flavor implementation should include:
1. Pingen provider flavor descriptor.
2. Adapter descriptor integration.
3. Pingen credential/config handling.
4. Letter creation or upload.
5. Auto-send flag support.
6. Address-position option mapping.
7. Validation result mapping.
8. Sending submission.
9. Track & Trace status polling.
10. Webhook ingestion for supported categories.
11. Return-mail / undeliverable event mapping.
12. Delivered-letter event mapping, product-dependent.
13. Evidence event generation.
14. Letter timeline.
15. Pingen evidence assessment.
16. Provider idempotency header usage.
17. Local idempotency protection.
### MVP Required Pingen Events
```text
delivery.payload.accepted
delivery.payload.rejected
payload.validation_passed
payload.validation_failed
delivery.payload.available
delivery.payload.submitted
delivery.production.started
delivery.postal.handed_over
delivery.postal.delivery_confirmed
delivery.postal.undeliverable
delivery.postal.return_received
delivery.postal.status_unknown
system.provider.degraded
system.provider.unavailable
```
Where a provider status is unavailable or semantically unclear, the adapter MUST emit the weakest safe event and preserve the raw status.
## 36. Pingen MVP Acceptance Criteria
The Pingen flavor MVP is acceptable when it can:
1. Accept a coordination-compatible `delivery.submit_letter` request.
2. Create or simulate a Pingen letter.
3. Preserve correlation and idempotency.
4. Use Pingen Idempotency-Key support where available.
5. Prevent duplicate physical sends for duplicate idempotency keys.
6. Support auto-send configuration.
7. Map validation success to `payload.validation_passed`.
8. Map letter issues or validation failure to `payload.validation_failed`.
9. Map send submission to `delivery.payload.submitted`.
10. Map sent-letter evidence conservatively.
11. Map delivered-letter evidence only when provider/product semantics support delivery confirmation.
12. Map undeliverable/return-mail evidence to strong negative delivery evidence.
13. Provide a Pingen letter timeline.
14. Provide a Pingen evidence assessment.
15. Integrate with `coordination-engine` without overclaiming physical delivery or human awareness.
## 37. Open Questions
1. Which exact Pingen native statuses map to `delivery.production.started`, `delivery.postal.handed_over`, and `delivery.postal.delivery_confirmed`?
2. Which event payload fields are present for Pingen webhook categories in the target API version?
3. How does the target Pingen account expose delivery-confirmation products?
4. Which return-mail details are available through API versus email/webhook?
5. Does the implementation need organization/workspace selection before letter creation?
6. Which Pingen country/product combinations are enabled for the target account?
7. How should configurable send limits be surfaced to coordination-engine policy?
8. How should staging/full-feature simulation be represented in evidence grades?
9. Which address-position values are available in the live API?
10. Should Pingen return details update a shared postal address quality registry?
## 38. Non-Goals
The Pingen flavor is not:
* a document authoring system.
* a PDF renderer by default.
* a legal notice system by itself.
* a postal carrier.
* a general Pingen UI replacement.
* the owner of coordination case success.
* the owner of contract, payment, or signature result semantics.
It integrates Pingen hybrid-mail capabilities into the coordination framework.
## 39. Summary
`HybridmailPingenSpecification.md` defines the Pingen provider flavor for `hybridmail-connect`.
The Pingen flavor models Pingen as a letter-centric hybrid-mail provider with:
* letter/file creation
* validation
* configurable address position
* auto-send/manual-send control
* Track & Trace
* webhook status categories
* sent-letter evidence
* delivered-letter evidence where product-supported
* undeliverable and return-mail evidence
* idempotency and rate-limit support
* staging/simulation support
The key rule is:
> Pingen events are provider, production, postal-chain, Track & Trace, and return-mail evidence. They are not automatic coordination result satisfaction. hybridmail-connect reports Pingen-channel facts and uncertainty. coordination-engine evaluates intended results.