[Tech Spec] ADYEN — VoidPostCapture
- Dominant language
- Python
- Stars
- 4
- Forks
- 6
- PR merge metrics
- No merged PRs in 30d
Description
# ADYEN — VoidPostCapture
**Complexity:** low
**Generated by:** Grace pipeline run `run-2026-05-13T20-46-35-097Z-06ded9`
## Summary
Implement VoidPostCapture payment method for ADYEN connector. Technical Specification — Adyen VoidPostCapture
## Scope
# Technical Specification — Adyen VoidPostCapture
## 1. Connector Profile
| Field | Value |
|-------|-------|
| Connector | Adyen |
| Flow | VoidPostCapture |
| API Family | Adyen Checkout API |
| API Version | v68 |
| Production Host | `https://{{merchant_endpoint_prefix}}-checkout-live.adyenpayments.com/checkout/` |
| Sandbox Host | `https://checkout-test.adyen.com/` |
| Regional Endpoints | Configurable via `endpoint_prefix` in connector config |
| Description | Adyen is a Dutch payment company with the status of an acquiring bank that allows businesses to accept e-commerce, mobile, and point-of-sale payments. |
## 2. Authentication
| Field | Detail |
|-------|--------|
| Scheme | API Key (Bearer-style header) |
| Header | `X-Api-Key` |
| Credentials Required | `api_key` (Secret), `merchant_account` (Secret) |
| Additional Config | `review_key` (optional, Secret), `endpoint_prefix` (optional, for live environment), `base_url`, `dispute_base_url` |
| Implementation | API key sent as `X-Api-Key` header value; `merchant_account` included in request body as `merchantAccount` |
## 3. Supported Flows
| Flow | HTTP | Path | Notes |
|------|------|------|-------|
| Authorize | POST | `/v68/payments` | Supports card, wallet, bank debit, BNPL, redirect methods |
| PSync | POST | `/v68/payments/details` | Payment sync for redirects; optional when no `encoded_data` |
| Capture | POST | `/v68/payments/{id}/captures` | Capture an authorized payment; `id` = `pspReference` |
| Void (Pre-Capture) | POST | `/v68/payments/{id}/cancels` | Cancel an authorized (uncaptured) payment |
| **VoidPostCapture** | POST | `/v68/payments/{id}/cancels` | Cancel/reverse a captured payment; same endpoint as Void but applied post-capture; Adyen processes as refund when payment is already captured |
| Refund | POST | `/v68/payments/{id}/refunds` | Partial or full refund on captured payment |
| RSync | — | — | Not implemented; relies on webhook `CANCELLATION` / `REFUND` events |
| Webhooks | P
## Out of Scope
Not specified in techspec
## Technical Constraints
- Follow existing connector patterns in the codebase
---
## Full Tech Spec
# Technical Specification — Adyen VoidPostCapture
## 1. Connector Profile
| Field | Value |
|-------|-------|
| Connector | Adyen |
| Flow | VoidPostCapture |
| API Family | Adyen Checkout API |
| API Version | v68 |
| Production Host | `https://{{merchant_endpoint_prefix}}-checkout-live.adyenpayments.com/checkout/` |
| Sandbox Host | `https://checkout-test.adyen.com/` |
| Regional Endpoints | Configurable via `endpoint_prefix` in connector config |
| Description | Adyen is a Dutch payment company with the status of an acquiring bank that allows businesses to accept e-commerce, mobile, and point-of-sale payments. |
## 2. Authentication
| Field | Detail |
|-------|--------|
| Scheme | API Key (Bearer-style header) |
| Header | `X-Api-Key` |
| Credentials Required | `api_key` (Secret), `merchant_account` (Secret) |
| Additional Config | `review_key` (optional, Secret), `endpoint_prefix` (optional, for live environment), `base_url`, `dispute_base_url` |
| Implementation | API key sent as `X-Api-Key` header value; `merchant_account` included in request body as `merchantAccount` |
## 3. Supported Flows
| Flow | HTTP | Path | Notes |
|------|------|------|-------|
| Authorize | POST | `/v68/payments` | Supports card, wallet, bank debit, BNPL, redirect methods |
| PSync | POST | `/v68/payments/details` | Payment sync for redirects; optional when no `encoded_data` |
| Capture | POST | `/v68/payments/{id}/captures` | Capture an authorized payment; `id` = `pspReference` |
| Void (Pre-Capture) | POST | `/v68/payments/{id}/cancels` | Cancel an authorized (uncaptured) payment |
| **VoidPostCapture** | POST | `/v68/payments/{id}/cancels` | Cancel/reverse a captured payment; same endpoint as Void but applied post-capture; Adyen processes as refund when payment is already captured |
| Refund | POST | `/v68/payments/{id}/refunds` | Partial or full refund on captured payment |
| RSync | — | — | Not implemented; relies on webhook `CANCELLATION` / `REFUND` events |
| Webhooks | POST | Merchant endpoint | `CANCELLATION` event for void confirmations; HMAC-SHA256 signed |
## 4. Request Schema Highlights
### VoidPostCapture Request (`AdyenVoidRequest`)
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `merchantAccount` | Secret\ | Yes | Merchant account code from connector config |
| `reference` | String | Yes | Merchant void reference ID (`connector_request_reference_id`) |
**Idempotency**: Adyen supports idempotent requests via the `Idempotency-Key` header (not currently wired in implementation).
**URL Construction**: Path parameter `{id}` is the `connector_transaction_id` (Adyen `pspReference`) from the original payment.
**Sample request** (from field probe):
```json
{
"merchantAccount": "probe_merchant",
"reference": "probe_void_001"
}
```
→ `POST https://checkout-test.adyen.com/v68/payments/probe_connector_txn_001/cancels`
**Key difference from pre-capture Void**: When applied to a captured payment, Adyen's `/cancels` endpoint automatically triggers a refund flow. The response status `received` indicates the cancellation/refund was accepted; `processing` indicates it is still being processed.
## 5. Response Schema Highlights
### VoidPostCapture Response (`AdyenVoidResponse`)
| Field | Type | Notes |
|-------|------|-------|
| `paymentPspReference` | String | PSP reference for the cancel/reversal request |
| `status` | `AdyenVoidStatus` | `received` or `processing` |
| `reference` | String | Merchant reference echoed back |
### Status Mapping
| Adyen `status` | Hyperswitch `AttemptStatus` | Meaning |
|-----------------|---------------------------|---------|
| `received` | `Voided` | Cancellation/reversal completed |
| `processing` | `VoidInitiated` | Cancellation/reversal in progress |
**Async completion**: When `status` is `processing`, the final result is delivered via the `CANCELLATION` webhook event.
### Error Response (`AdyenErrorResponse`)
| Field | Type | Notes |
|-------|------|-------|
| `status` | i32 | HTTP-equivalent status code |
| `errorCode` | String | Adyen error code |
| `message` | String | Human-readable error description |
| `errorType` | String | Error classification |
| `pspReference` | Option\ | PSP reference (if available) |
## 6. Error Handling
| HTTP | `status` / `errorCode` | Cause |
|------|------------------------|-------|
| 401 | Invalid credential | Invalid or missing API key |
| 403 | 901 | Forbidden — merchant not authorized for operation |
| 422 | 200 | Invalid data — malformed request body or missing required fields |
| 422 | 101 | Invalid merchant account — `merchantAccount` not found |
| 404 | — | Payment not found — `pspReference` does not exist |
| 409 | — | Conflict — payment already cancelled or in incompatible state |
| 422 | 702 | Payment already captured — cannot cancel; use refund endpoint |
| 5xx | — | Adyen server error; retry with idempotency key |
## 7. Webhooks / Async Notifications
| Aspect | Detail |
|--------|--------|
| Event Code | `CANCELLATION` — fires when a `/cancels` request completes |
| Success field | `"true"` or `"false"` |
| Delivery | HTTP POST to merchant webhook endpoint |
| Format | `{"notificationItems":[{"NotificationRequestItem":{...}}]}` |
| Verification | HMAC-SHA256 signature in `additionalData.hmacSignature` |
| HMAC Message | `pspReference:originalReference:merchantAccountCode:merchantReference:amount.value:amount.currency:eventCode:success` |
| HMAC Key | Hex-decoded webhook secret from `ConnectorWebhookSecrets.secret` |
| Comparison | Base64-encoded computed HMAC vs. received `hmacSignature` |
| Retry Policy | Adyen retries failed deliveries with exponential backoff (up to 5 days) |
| Acknowledgment | Respond with `[accepted]` (HTTP 200) |
| Webhook Status Mapping | `CANCELLATION` + `success=true` → `Voided`; `CANCELLATION` + `success=false` → `VoidFailed` |
| Documented Gaps | Source verification is currently marked as non-mandatory (`is_webhook_source_verification_mandatory` returns `false`) |
## 8. References
1. Adyen Checkout API v68 — Payments: https://docs.adyen.com/api-explorer/Checkout/68/post/payments
2. Adyen Checkout API v68 — Cancel payment: https://docs.adyen.com/api-explorer/Checkout/68/post/payments/-paymentPspReference-/cancels
3. Adyen Checkout API v68 — Capture: https://docs.adyen.com/api-explorer/Checkout/68/post/payments/-paymentPspReference-/captures
4. Adyen Checkout API v68 — Refund: https://docs.adyen.com/api-explorer/Checkout/68/post/payments/-paymentPspReference-/refunds
5. Adyen Webhooks: https://docs.adyen.com/development-resources/webhooks
6. Adyen HMAC Signature Verification: https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures
7. Adyen Cancel or Refund: https://docs.adyen.com/online-payments/cancel-or-refund
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.