Clearing House Outbound Payments Blueprint
Clearing house outbound payment operations including credit transfers, bulk payments, direct debits, returns, and cancellations
| Feature | clearing-house-outbound-payments |
| Category | Integration |
| Version | 1.0.0 |
| Tags | payments, clearing-house, outbound, credit-transfer, direct-debit |
| YAML Source | View on GitHub |
| JSON API | clearing-house-outbound-payments.json |
Actors
| ID | Name | Type | Description |
|---|---|---|---|
partner_system | Partner System | system | Financial institution sending payments via Electrum’s API |
payment_platform | Payment Orchestration Platform | external | Payment platform orchestrating payment processing through the national payment system |
clearing_house | Clearing House Operator | external | Clearing house scheme operator for payment clearing and settlement |
creditor_bank | Creditor Bank | external | Receiving/creditor financial institution |
Fields
| Name | Type | Required | Label | Description |
|---|---|---|---|---|
uetr | token | Yes | UETR | |
end_to_end_identification | text | Yes | End-to-End Identification | Validations: maxLength |
transaction_reference | text | Yes | Transaction Reference | |
creditor_account_number | text | Yes | Creditor Account Number | |
creditor_account_type | select | No | Creditor Account Type | |
creditor_bank_code | text | No | Creditor Bank Code | |
debtor_account_number | text | Yes | Debtor Account Number | |
debtor_account_type | select | No | Debtor Account Type | |
amount_value | number | Yes | Amount | Validations: min |
amount_currency | text | Yes | Currency | |
payment_scheme | select | Yes | Payment Scheme | |
payment_information | text | No | Payment Information | |
remittance_information | text | No | Remittance Information | |
instruction_priority | text | No | Instruction Priority | |
mandate_reference | text | No | Mandate Reference | |
return_reason | text | No | Return Reason | |
cancellation_type | text | No | Cancellation Type |
States
State field: transaction_status
Values:
| State | Initial | Terminal |
|---|---|---|
initiated | Yes | |
submitted | ||
processing | ||
completed | Yes | |
rejected | Yes | |
returned | Yes | |
cancelled | Yes | |
failed | Yes |
Transitions:
| Name | From | To | Actor | Condition |
|---|---|---|---|---|
initiated | submitted | electrum | ||
submitted | processing | bankservafrica | ||
processing | completed | creditor_bank | ||
processing | rejected | bankservafrica | ||
submitted | rejected | bankservafrica | ||
completed | returned | partner_system | ||
processing | cancelled | partner_system | ||
initiated | failed | electrum | ||
submitted | failed | electrum |
Rules
- async_processing:
- http_202_acknowledgement: All outbound operations return HTTP 202 — responses are delivered asynchronously via partner API callbacks
- authentication:
- oauth2_required: OAuth 2.0 authentication required for all API operations
- idempotency:
- duplicate_handling: Idempotent processing for retries — duplicate requests return HTTP 409 Conflict with original error echoed
- sla_constraints:
- payshap_end_to_end: PayShap: 10 second end-to-end for proxy resolution and payment
- rtc_end_to_end: RTC: 60 second end-to-end
- uetr:
- universally_unique: UETR must be universally unique for end-to-end tracking across all participants
- error_response:
- schema: ErrorDetail
- required_fields: message (required), detail (optional)
- identifier_determination:
- payshap_only: PayShap requires identifier determination before credit transfer — Electrum delivers report to partner’s /identifiers/outbound/identifier-determination-report endpoint
SLA
| Scope | Max Duration | Escalation |
|---|---|---|
| acknowledgement | immediate | |
| payshap_end_to_end | 10s | |
| rtc_end_to_end | 60s |
Outcomes
Credit_transfer_initiated (Priority: 1)
Given:
- Partner is authenticated via OAuth 2.0
payment_scheme(input) inZA_RTC,ZA_RPPamount_value(input) gte0
Then:
- call_service target:
electrum_api.outbound_credit_transfer— POST /transactions/outbound/credit-transfer - emit_event event:
outbound.credit_transfer.initiated - transition_state field:
transaction_statusto:initiated
Result: HTTP 202 returned — credit transfer accepted for async processing
Credit_transfer_success (Priority: 2)
Given:
- Outbound credit transfer was initiated
- Positive response received from scheme via creditor bank
Then:
- call_service target:
electrum_api.deliver_credit_transfer_response— Electrum delivers response to partner’s /transactions/outbound/credit-transfer-response - emit_event event:
outbound.credit_transfer.response_received - transition_state field:
transaction_statusfrom:processingto:completed
Result: Credit transfer completed — partner receives positive response at callback endpoint
Credit_transfer_rejected (Priority: 3)
Given:
- Outbound credit transfer was initiated
- Negative response received from scheme or creditor bank
Then:
- call_service target:
electrum_api.deliver_credit_transfer_response— Electrum delivers rejection to partner’s /transactions/outbound/credit-transfer-response - emit_event event:
outbound.credit_transfer.response_received - transition_state field:
transaction_statusfrom:processingto:rejected
Result: Credit transfer rejected — partner receives negative response with reason at callback endpoint
Bulk_credit_transfer_initiated (Priority: 4)
Given:
- Partner is authenticated via OAuth 2.0
amount_value(input) gte0
Then:
- call_service target:
electrum_api.outbound_bulk_credit_transfer— POST /transactions/outbound/bulk/credit-transfer - emit_event event:
outbound.bulk_credit_transfer.initiated - transition_state field:
transaction_statusto:initiated
Result: HTTP 202 returned — bulk credit transfer accepted for async processing
Direct_debit_initiated (Priority: 5)
Given:
- Partner is authenticated via OAuth 2.0
mandate_reference(input) existsamount_value(input) gte0
Then:
- call_service target:
electrum_api.outbound_direct_debit— POST /transactions/outbound/direct-debit - emit_event event:
outbound.direct_debit.initiated - transition_state field:
transaction_statusto:initiated
Result: HTTP 202 returned — direct debit accepted for async processing
Payment_return_initiated (Priority: 6)
Given:
- Partner is authenticated via OAuth 2.0
return_reason(input) exists- Original inbound payment exists and is eligible for return
Then:
- call_service target:
electrum_api.outbound_payment_return— POST /transactions/outbound/payment-return - emit_event event:
outbound.payment_return.initiated - transition_state field:
transaction_statusto:initiated
Result: HTTP 202 returned — payment return accepted for async processing
Payment_cancellation_initiated (Priority: 7)
Given:
- Partner is authenticated via OAuth 2.0
cancellation_type(input) exists- Prior payment instruction exists and is eligible for cancellation
Then:
- call_service target:
electrum_api.outbound_payment_cancellation— POST /transactions/outbound/payment-cancellation - emit_event event:
outbound.payment_cancellation.initiated - transition_state field:
transaction_statusto:initiated
Result: HTTP 202 returned — cancellation request accepted; resolution delivered to partner’s inbound cancellation resolution endpoint
Status_query_sent (Priority: 8)
Given:
- Partner is authenticated via OAuth 2.0
uetr(input) exists
Then:
- call_service target:
electrum_api.outbound_status_request— POST /transactions/outbound/credit-transfer/status-request or /transactions/outbound/bulk/credit-transfer/status-request - emit_event event:
outbound.status_request.sent
Result: Status request sent — current transaction state returned
Outbound_technical_error (Priority: 9) — Error: OUTBOUND_SERVER_ERROR
Given:
- Outbound request was initiated
- Technical error occurs during Electrum processing
Then:
- emit_event event:
outbound.credit_transfer.response_received - transition_state field:
transaction_statusfrom:initiatedto:failed
Result: Technical error — partner receives error response via callback with ErrorDetail schema
Outbound_duplicate_request (Priority: 10) — Error: OUTBOUND_CONFLICT
Given:
- Partner sends an outbound request
- Request is a duplicate of a previously processed request
Then:
- set_field target:
http_statusvalue:409
Result: HTTP 409 Conflict returned — original error echoed in response body
Errors
| Code | Status | Message | Retry |
|---|---|---|---|
OUTBOUND_BAD_REQUEST | 400 | Invalid request payload or missing required fields | No |
OUTBOUND_UNAUTHORIZED | 401 | OAuth 2.0 authentication failed or token expired | No |
OUTBOUND_FORBIDDEN | 403 | Insufficient permissions for the requested operation | No |
OUTBOUND_NOT_FOUND | 404 | Requested resource or transaction not found | No |
OUTBOUND_METHOD_NOT_ALLOWED | 400 | HTTP method not allowed for this endpoint | No |
OUTBOUND_CONFLICT | 409 | Duplicate request detected — original error echoed in response | No |
OUTBOUND_UNPROCESSABLE | 422 | Request is syntactically valid but cannot be processed | No |
OUTBOUND_RATE_LIMITED | 429 | Rate limit exceeded — retry after backoff | No |
OUTBOUND_SERVER_ERROR | 500 | Internal server error on Electrum platform | No |
OUTBOUND_SERVICE_UNAVAILABLE | 500 | Electrum service temporarily unavailable | No |
Events
| Event | Description | Payload |
|---|---|---|
outbound.credit_transfer.initiated | uetr, end_to_end_identification, transaction_reference, payment_scheme, amount_value, amount_currency | |
outbound.credit_transfer.response_received | uetr, end_to_end_identification, transaction_status | |
outbound.bulk_credit_transfer.initiated | uetr, transaction_reference, payment_scheme, amount_value | |
outbound.bulk_credit_transfer.response_received | uetr, transaction_status | |
outbound.direct_debit.initiated | uetr, end_to_end_identification, mandate_reference, amount_value | |
outbound.direct_debit.response_received | uetr, transaction_status | |
outbound.payment_return.initiated | uetr, end_to_end_identification, return_reason, amount_value | |
outbound.payment_cancellation.initiated | uetr, end_to_end_identification, cancellation_type | |
outbound.status_request.sent | uetr, end_to_end_identification | |
outbound.identifier.report_received | uetr, end_to_end_identification |
Related Blueprints
| Feature | Relationship | Reason |
|---|---|---|
| chp-inbound-payments | recommended | Inbound payment processing — receiving payments from the national payment system |
| chp-request-to-pay | optional | Request-to-pay operations via PayShap |
| chp-eft | recommended | EFT-specific payment operations |
| chp-account-management | recommended | Account verification and management for CHP participants |
| payshap-rail | optional | Real-time payment rail abstraction built on top of clearing house PayShap scheme |
AGI Readiness
Goals
Reliable Clearing House Outbound Payments
Clearing house outbound payment operations including credit transfers, bulk payments, direct debits, returns, and cancellations
Success Metrics:
| Metric | Target | Measurement |
|---|---|---|
| success_rate | >= 99.5% | Successful operations divided by total attempts |
| error_recovery_rate | >= 95% | Errors that auto-recover without manual intervention |
Constraints:
- availability (non-negotiable): Must degrade gracefully when dependencies are unavailable
- security (non-negotiable): Sensitive fields must be encrypted at rest and never logged in plaintext
Autonomy
Level: supervised
Escalation Triggers:
error_rate > 5
Verification
Invariants:
- sensitive fields are never logged in plaintext
- all data access is authenticated and authorized
- error messages never expose internal system details
- state transitions follow the defined state machine — no illegal transitions
Tradeoffs
| Prefer | Over | Reason |
|---|---|---|
| reliability | throughput | integration failures can cascade across systems |
Safety
| Action | Permission | Cooldown | Max Auto |
|---|---|---|---|
| credit_transfer_initiated | autonomous | - | - |
| credit_transfer_success | autonomous | - | - |
| credit_transfer_rejected | supervised | - | - |
| bulk_credit_transfer_initiated | autonomous | - | - |
| direct_debit_initiated | autonomous | - | - |
| payment_return_initiated | autonomous | - | - |
| payment_cancellation_initiated | supervised | - | - |
| status_query_sent | autonomous | - | - |
| outbound_technical_error | autonomous | - | - |
| outbound_duplicate_request | autonomous | - | - |