PACS.028 Payment Status Query
ISO 20022 PACS.028 Payment Status Request API documentation for querying transfer status on the StrongholdNET network.
PACS.028 Payment Status Query API Documentation
Overview
The PACS.028 endpoint processes ISO 20022 Payment Status Request messages and returns PACS.002 Payment Status Report responses with current transfer status. This endpoint provides standards-compliant status inquiry for transfers previously submitted via PACS.008.
Endpoint: POST /v1/pacs028/{network}
Supported Networks:
shnet- Stronghold Network
Content Types:
- Request:
application/xmlortext/xml - Response:
application/xml
Authentication
All requests require API key authentication via the SHNET-API-KEY header:
POST /v1/pacs028/shnet
Content-Type: application/xml
SHNET-API-KEY: your-api-key-hereRequest Format (PACS.028)
Minimal PACS.028 Example for SHNET Network
Field Markers:
- [VALIDATION] = Required for format validation to pass
- [QUERY] = Required for transfer lookup
- [OPTIONAL] = Not required but recommended for tracking/auditing
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.028.001.06">
<!-- [VALIDATION] FIToFIPmtStsReq: Root status request element - REQUIRED -->
<FIToFIPmtStsReq>
<!-- [VALIDATION] GrpHdr: Group Header - REQUIRED -->
<GrpHdr>
<!-- [VALIDATION] MsgId: SHNET format {UnixTimestamp}{Random10Hex} - REQUIRED
- First 10 chars: Unix timestamp in UTC (seconds since epoch)
- Last 10 chars: Random hexadecimal (0-9A-F uppercase)
- Timestamp must be no older than 24 hours (prevents replay attacks)
- Timestamp must be no more than 5 minutes in the future (clock skew tolerance)
- Example: 1732675800A3F2B7E156 -->
<MsgId>1732675800A3F2B7E156</MsgId>
<!-- [OPTIONAL] CreDtTm: Message creation timestamp (ISO 8601)
Not validated but recommended for auditing -->
<CreDtTm>2024-11-27T10:30:00Z</CreDtTm>
</GrpHdr>
<!-- [QUERY] TxInf: Transaction Inquiry - REQUIRED
Use this to specify which transfer you want to query -->
<TxInf>
<!-- [QUERY] OrgnlInstrId: Transfer ID - STRONGLY RECOMMENDED
Use the UUID transfer ID from the PACS.002 acceptance response
This is the transfer ID from: <AddtlInf>TransferId: {uuid}</AddtlInf>
Example: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e -->
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
<!-- [OPTIONAL] OrgnlEndToEndId: Alternative transfer ID location
If OrgnlInstrId is not provided, the transfer ID can be placed here -->
<!-- <OrgnlEndToEndId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlEndToEndId> -->
</TxInf>
</FIToFIPmtStsReq>
</Document>How to Get the Transfer ID
The transfer ID is provided in the PACS.002 acceptance response when you submit a PACS.008:
<!-- From PACS.002 acceptance response -->
<TxInfAndSts>
<TxSts>ACCP</TxSts>
<StsRsnInf>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
</StsRsnInf>
</TxInfAndSts>Extract the UUID from the TransferId: {uuid} field and use it in the OrgnlInstrId field of your PACS.028 request.
Response Format (PACS.002)
Success Response - Transfer Created (HTTP 200)
When querying a newly created transfer that hasn't started processing yet:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<!-- Response Group Header -->
<GrpHdr>
<MsgId>RESP-1732675850-M3N4O5P6</MsgId>
<CreDtTm>2024-11-27T10:30:50Z</CreDtTm>
</GrpHdr>
<!-- Transaction Information and Status -->
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
<!-- Status: ACSP = Accepted Settlement In Process -->
<TxSts>ACSP</TxSts>
<StsRsnInf>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
<AddtlInf>Status: Created</AddtlInf>
<AddtlInf>CreatedAt: 2024-11-27T10:30:00Z</AddtlInf>
</StsRsnInf>
<!-- Original Transaction Reference -->
<OrgnlTxRef>
<IntrBkSttlmAmt Ccy="USD">1000.00</IntrBkSttlmAmt>
</OrgnlTxRef>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: ACSP - Accepted Settlement In Process
Success Response - Transfer Processing (HTTP 200)
When querying a transfer that is currently being processed:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732675900-A1B2C3D4</MsgId>
<CreDtTm>2024-11-27T10:31:40Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
<TxSts>ACSP</TxSts>
<StsRsnInf>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
<AddtlInf>Status: Processing</AddtlInf>
<AddtlInf>CreatedAt: 2024-11-27T10:30:00Z</AddtlInf>
<AddtlInf>UpdatedAt: 2024-11-27T10:30:45Z</AddtlInf>
</StsRsnInf>
<OrgnlTxRef>
<IntrBkSttlmAmt Ccy="USD">1000.00</IntrBkSttlmAmt>
</OrgnlTxRef>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: ACSP - Accepted Settlement In Process
Success Response - Transfer Completed (HTTP 200)
When querying a successfully completed transfer:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732676000-E5F6G7H8</MsgId>
<CreDtTm>2024-11-27T10:33:20Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
<!-- Status: ACSC = Accepted Settlement Completed -->
<TxSts>ACSC</TxSts>
<StsRsnInf>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
<AddtlInf>Status: Completed</AddtlInf>
<AddtlInf>CompletedAt: 2024-11-27T10:32:15Z</AddtlInf>
<!-- Stellar blockchain transaction hash -->
<AddtlInf>TransactionHash: 7b3e4f9a8c1d2e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0</AddtlInf>
</StsRsnInf>
<OrgnlTxRef>
<!-- Source amount (original USD) -->
<IntrBkSttlmAmt Ccy="USD">1000.00</IntrBkSttlmAmt>
<!-- Destination amount (converted to SHX tokens) -->
<Amt>
<InstdAmt Ccy="SHX">50000.00</InstdAmt>
</Amt>
</OrgnlTxRef>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: ACSC - Accepted Settlement Completed
- Includes Stellar transaction hash for blockchain verification
- Shows both source (USD) and destination (SHX) amounts
Error Response - Transfer Failed (HTTP 200)
When querying a transfer that failed during processing:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732676100-I9J0K1L2</MsgId>
<CreDtTm>2024-11-27T10:35:00Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
<!-- Status: RJCT = Rejected -->
<TxSts>RJCT</TxSts>
<StsRsnInf>
<!-- Reason code explaining why it failed -->
<Rsn>
<Cd>AC01</Cd>
</Rsn>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
<AddtlInf>Status: Failed</AddtlInf>
<AddtlInf>ErrorCode: AC01</AddtlInf>
<AddtlInf>UpdatedAt: 2024-11-27T10:34:30Z</AddtlInf>
</StsRsnInf>
<OrgnlTxRef>
<IntrBkSttlmAmt Ccy="USD">1000.00</IntrBkSttlmAmt>
</OrgnlTxRef>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: RJCT - Rejected
Reason Code: AC01 - Incorrect Account Number (or other failure reason)
Rejection Response - Transfer Not Found (HTTP 404)
When querying a transfer ID that doesn't exist or doesn't belong to your organization:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732676200-Q7R8S9T0</MsgId>
<CreDtTm>2024-11-27T10:36:40Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>018c5e5d-9999-9999-9999-999999999999</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>AC01</Cd>
</Rsn>
<AddtlInf>Transfer not found: 018c5e5d-9999-9999-9999-999999999999</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Reason Code: AC01 - Incorrect Account Number (transfer not found)
Rejection Response - Missing Transfer ID (HTTP 400)
When the PACS.028 request is missing the transfer ID:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732676300-U1V2W3X4</MsgId>
<CreDtTm>2024-11-27T10:38:20Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>NOTPROVIDED</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>NARR</Cd>
</Rsn>
<AddtlInf>Transfer ID not found in OrgnlInstrId or OrgnlEndToEndId. Please provide the transfer ID from the PACS.002 acceptance response.</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Reason Code: NARR - Narrative (missing required information)
Rejection Response - Invalid Message Format (HTTP 400)
When the PACS.028 XML is malformed or doesn't match the schema:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732676400-Y5Z6A7B8</MsgId>
<CreDtTm>2024-11-27T10:40:00Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>NOTPROVIDED</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>FF01</Cd>
</Rsn>
<AddtlInf>Invalid PACS.028 XML: Element 'FIToFIPmtStsReq' not found</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Reason Code: FF01 - Invalid File Format
Status Codes
Transaction Status Codes (TxSts)
| Code | Name | Description | Transfer State |
|---|---|---|---|
ACSP | Accepted Settlement In Process | Transfer is created or being processed | Created, Processing |
ACSC | Accepted Settlement Completed | Transfer completed successfully | Completed |
RJCT | Rejected | Transfer failed or not found | Failed, Not Found |
HTTP Status Codes
| HTTP Code | Scenario | PACS.002 Status |
|---|---|---|
| 200 | Status report returned successfully | ACSP, ACSC, RJCT |
| 400 | Invalid request format, missing transfer ID | RJCT |
| 401 | Authentication failed (no PACS.002 sent) | N/A |
| 404 | Transfer not found | RJCT |
| 500 | Internal server error | RJCT |
Transfer Status Mapping
| Internal Status | ISO 20022 Code | Description | Additional Information |
|---|---|---|---|
| Created | ACSP | Accepted Settlement In Process | Transfer queued, not yet started |
| Processing | ACSP | Accepted Settlement In Process | Transfer actively processing |
| Completed | ACSC | Accepted Settlement Completed | Includes transaction hash |
| Failed | RJCT | Rejected | Includes error code and reason |
Reason Codes
| Code | Name | Description | Example Scenario |
|---|---|---|---|
FF01 | Invalid File Format | XML parsing/schema validation errors | Malformed XML, missing elements |
AC01 | Incorrect Account Number | Transfer ID not found or invalid | Non-existent transfer ID |
NARR | Narrative | Generic reason with custom explanation | Missing transfer ID, other errors |
Network-Specific Validation (shnet)
SHNET Message ID Format (REQUIRED)
Format: {UnixTimestamp}{Random10Hex}
- Total Length: 20 characters
- First 10 characters: Unix timestamp in seconds (e.g.,
1732675800) - Last 10 characters: Random hexadecimal (0-9A-F uppercase)
- Example:
1732675800A3F2B7E156
Validation Rules:
- ✅ Message timestamp must be within 24 hours of current time (prevents replay attacks)
- ✅ Message timestamp cannot be more than 5 minutes in the future (clock skew tolerance)
- ❌ Old messages (>24h) are rejected to prevent replay attacks
- ❌ Future messages (>5min ahead) are rejected
Generate Timestamp:
# Unix/Mac
date +%s
# PowerShell
[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
# Node.js
Math.floor(Date.now() / 1000)
# Python
import time; int(time.time())Generate Full Message ID:
# Example in bash
echo "$(date +%s)$(openssl rand -hex 5 | tr '[:lower:]' '[:upper:]')"
# Output: 1732675800A3F2B7E156Required Fields for Validation
Minimum fields to pass validation:
FIToFIPmtStsReq- Root elementGrpHdr/MsgId- SHNET format message IDTxInf/OrgnlInstrIdORTxInf/OrgnlEndToEndId- Transfer ID (valid UUID format)
Transfer ID Format
- Format: UUID v7 (e.g.,
018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e) - Source: Extracted from PACS.002 acceptance response
- Field:
<AddtlInf>TransferId: {uuid}</AddtlInf> - Validation: Must be a valid UUID format
- Scope: Only transfers belonging to your organization can be queried
Single Transaction Limitation
IMPORTANT: Only single transaction status queries are supported per request.
- ✅ Supported: One
TxInfelement per PACS.028 request - ❌ Not Supported: Multiple
TxInfelements in the same request
If you send multiple transactions:
<!-- This will be REJECTED -->
<FIToFIPmtStsReq>
<GrpHdr>...</GrpHdr>
<TxInf><OrgnlInstrId>transfer_1</OrgnlInstrId></TxInf>
<TxInf><OrgnlInstrId>transfer_2</OrgnlInstrId></TxInf>
<TxInf><OrgnlInstrId>transfer_3</OrgnlInstrId></TxInf>
</FIToFIPmtStsReq>Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>NARR</Cd></Rsn>
<AddtlInf>Only single transaction status queries are supported. Found 3 transactions. Please submit separate PACS.028 requests for each transfer ID.</AddtlInf>
</StsRsnInf>For batch queries:
- Submit separate PACS.028 requests for each transfer ID
- Consider using pagination with appropriate delays
- Future: A dedicated batch status endpoint may be added (REST API)
Error Scenarios & Examples
Scenario 1: Query Transfer That Doesn't Exist
Request: PACS.028 with non-existent transfer ID
Response (HTTP 404):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>AC01</Cd></Rsn>
<AddtlInf>Transfer not found: 018c5e5d-9999-9999-9999-999999999999</AddtlInf>
</StsRsnInf>Scenario 2: Query Transfer From Another Organization
Request: PACS.028 with transfer ID from different organization
Response (HTTP 404):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>AC01</Cd></Rsn>
<AddtlInf>Transfer not found: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
</StsRsnInf>Note: For security reasons, the error message is the same whether the transfer doesn't exist or belongs to another organization.
Scenario 3: Missing Transfer ID in Request
Request: PACS.028 without OrgnlInstrId or OrgnlEndToEndId
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>NARR</Cd></Rsn>
<AddtlInf>Transfer ID not found in OrgnlInstrId or OrgnlEndToEndId. Please provide the transfer ID from the PACS.002 acceptance response.</AddtlInf>
</StsRsnInf>Scenario 4: Invalid SHNET Message ID Format
Request: PACS.028 with <MsgId>INVALID-MSG-ID</MsgId>
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>FF01</Cd></Rsn>
<AddtlInf>Invalid SHNET message ID format. Expected: {UnixTimestamp}{Random10Hex} (e.g., 1730103000A3F2B7E156)</AddtlInf>
</StsRsnInf>Scenario 5: Invalid Network
Request: POST /v1/pacs028/swift (unsupported network)
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>NARR</Cd></Rsn>
<AddtlInf>Network 'swift' is not supported. Supported networks: shnet</AddtlInf>
</StsRsnInf>Scenario 6: Multiple Transactions in Single Request
Request: PACS.028 with multiple TxInf elements
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>NARR</Cd></Rsn>
<AddtlInf>Only single transaction status queries are supported. Found 3 transactions. Please submit separate PACS.028 requests for each transfer ID.</AddtlInf>
</StsRsnInf>Reason Code: NARR - Narrative (multiple transactions not supported)
Complete Usage Flow
Step 1: Submit a Transfer (PACS.008)
curl -X POST https://api.shnet.io/v1/pacs008/shnet \
-H "Content-Type: application/xml" \
-H "SHNET-API-KEY: your-api-key" \
-d @pacs008_request.xmlStep 2: Extract Transfer ID from Response
<!-- From PACS.002 acceptance response -->
<StsRsnInf>
<AddtlInf>TransferId: 018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</AddtlInf>
</StsRsnInf>Step 3: Query Transfer Status (PACS.028)
curl -X POST https://api.shnet.io/v1/pacs028/shnet \
-H "Content-Type: application/xml" \
-H "SHNET-API-KEY: your-api-key" \
-d @pacs028_request.xmlpacs028_request.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.028.001.06">
<FIToFIPmtStsReq>
<GrpHdr>
<MsgId>1732675900A3F2B7E156</MsgId>
<CreDtTm>2024-11-27T10:31:40Z</CreDtTm>
</GrpHdr>
<TxInf>
<OrgnlInstrId>018c5e5d-4f1a-7a3b-9c2e-8f4d6b9a1c3e</OrgnlInstrId>
</TxInf>
</FIToFIPmtStsReq>
</Document>Step 4: Receive Status Report (PACS.002)
<!-- Response shows current status -->
<TxSts>ACSP</TxSts> <!-- or ACSC for completed, RJCT for failed -->
<StsRsnInf>
<AddtlInf>Status: Processing</AddtlInf>
<AddtlInf>UpdatedAt: 2024-11-27T10:31:30Z</AddtlInf>
</StsRsnInf>Best Practices
Transfer ID Management
IMPORTANT: Store the transfer ID from the PACS.002 acceptance response for future status queries.
- Extract from PACS.002: Parse the
TransferId: {uuid}fromAddtlInf - Store Securely: Save the UUID in your database linked to the payment
- Use for Queries: Include in
OrgnlInstrIdfield of PACS.028 requests
Message ID Generation for SHNET
Required Format: {UnixTimestamp}{Random10Hex}
- Total: 20 characters
- First 10 chars: Unix timestamp (seconds)
- Last 10 chars: Random uppercase hexadecimal
- Example:
1732675800A3F2B7E156
Generation Examples:
# Bash/Unix
echo "$(date +%s)$(openssl rand -hex 5 | tr '[:lower:]' '[:upper:]')"
# PowerShell
$ts = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
$rnd = -join ((0..4) | ForEach-Object { '{0:X2}' -f (Get-Random -Max 256) })
"$ts$rnd"
# Node.js
const ts = Math.floor(Date.now() / 1000);
const rnd = crypto.randomBytes(5).toString('hex').toUpperCase();
`${ts}${rnd}`Polling Strategy
- Don't Poll Too Frequently: Wait at least 5-10 seconds between status checks
- Exponential Backoff: Increase wait time if transfer is still processing
- Set Maximum Retries: Stop polling after a reasonable timeout (e.g., 5 minutes)
- Handle All Status Codes: Check for
ACSP,ACSC,RJCT
Error Handling
- Always check HTTP status code first
- Parse PACS.002 response for detailed status information
- Log transfer ID for correlation and debugging
- Implement retry logic for network errors (500, 503)
- Don't retry on 404 (transfer not found) or 400 (validation errors)
Security
- Never share API keys
- Store transfer IDs securely
- Use HTTPS for all API calls
- Implement proper authentication error handling
- Message IDs are unique (timestamp + random) - never reuse
Testing
- Submit Test Transfer First: Use PACS.008 to create a transfer
- Store Transfer ID: Save the ID from the acceptance response
- Query Immediately: Test status query while transfer is still processing
- Query After Completion: Verify completed transfers show correct status
- Test Error Cases: Query with invalid/non-existent transfer IDs
Additional Information Returned
For All Transfers
- TransferId: Internal transfer UUID
- Status: Current transfer state (Created, Processing, Completed, Failed)
- CreatedAt: When transfer was initially created
- IntrBkSttlmAmt: Original source amount and currency
For Processing Transfers
- UpdatedAt: Last time transfer status was updated
For Completed Transfers
- CompletedAt: When transfer was completed
- TransactionHash: Stellar blockchain transaction hash for verification
- Amt/InstdAmt: Destination amount in SHX tokens
- UpdatedAt: Final update timestamp
For Failed Transfers
- ErrorCode: ISO 20022 reason code explaining the failure
- UpdatedAt: When the transfer failed
Message Persistence & Audit Trail
Automatic Message Storage
All PACS.028 requests are automatically persisted to the database for:
- ✅ Audit Trail - Track who queried what transfer and when
- ✅ Compliance - Meet regulatory requirements for message logging
- ✅ Debugging - Troubleshoot client issues with query requests
- ✅ Analytics - Analyze query patterns and usage
What Gets Stored
For every PACS.028 request, the system stores:
| Field | Example | Purpose |
|---|---|---|
| MessageType | pacs.028 | Identifies message as status query |
| MessageId | 1732675800A3F2B7E156 | Unique message identifier |
| OriginalInstructionId | transfer_uuid | Transfer ID being queried |
| OriginalEndToEndId | Alternative ID | Alternative transfer ID (if provided) |
| OriginalMessageId | Original PACS.008 ID | Message being queried (if provided via OrgnlGrpInf) |
| RawXmlContent | Full XML | Complete request for debugging |
| OrganizationId | Your org ID | Organization making the query |
| ApiEnvironment | Sandbox/Production | Environment context |
| Network | Shnet | Payment network |
| CreatedAt | Timestamp | When query was made |
Querying Stored Messages
Messages are stored in the iso20022_messages table and can be queried for operational insights:
-- View your organization's recent PACS.028 queries
SELECT
id,
message_id,
identifiers->>'instruction_id' as transfer_id,
created_at
FROM iso20022_messages
WHERE
message_type = 'pacs.028'
AND organization_id = 'your_org_id'
ORDER BY created_at DESC
LIMIT 100;Batch Query Alternatives
Why Single-Transaction Design?
The PACS.028 endpoint is designed for single-transaction queries because:
- ✅ Real-time use case - Most queries are for individual transfers
- ✅ Simpler implementation - Easier to maintain and optimize
- ✅ Industry standard - Matches SWIFT, FedNow approaches
- ✅ Consistent with PACS.008 - Both endpoints use single-transaction pattern
If You Need Batch Queries
Option 1: Sequential Requests (Current)
# Query multiple transfers with small delays
for transfer_id in transfer_1 transfer_2 transfer_3; do
curl -X POST https://api.shnet.io/v1/pacs028/shnet \
-H "SHNET-API-KEY: your-key" \
-d "@pacs028_${transfer_id}.xml"
sleep 1 # Prevent rate limiting
doneOption 2: Future REST Batch Endpoint (Planned)
# Future: Batch status endpoint (not yet implemented)
curl -X POST https://api.shnet.io/v1/transfers/batch-status \
-H "SHNET-API-KEY: your-key" \
-H "Content-Type: application/json" \
-d '{
"transfer_ids": ["transfer_1", "transfer_2", "transfer_3"]
}'Recommendation:
- For 1-10 transfers: Use separate PACS.028 requests
- For 10+ transfers: Consider REST batch endpoint (contact support for availability)
- For real-time monitoring: Use webhooks (future feature)
Test Coverage
The PACS.028 endpoint has comprehensive test coverage including:
Unit Tests (25 tests)
- ✅ Success scenarios (transfer found, all statuses)
- ✅ Error scenarios (not found, missing ID, invalid format)
- ✅ Edge cases (fallback to EndToEndId, empty IDs)
- ✅ Logging verification (success, warning, error logs)
- ✅ Configuration validation (network, document validation)
- ✅ Message storage failure (database failures)
- ✅ Infrastructure tests (missing/wrong type in HttpContext)
Integration Tests (15 tests)
- ✅ End-to-end status queries (Created, Processing, Completed, Failed)
- ✅ Database persistence verification
- ✅ Transfer lookup (found, not found, invalid ID)
- ✅ Validation (message ID format, timestamps, network)
- ✅ Authentication (valid key, missing key)
- ✅ Fallback scenarios (EndToEndId when InstrId invalid)
Validator Tests (43 tests)
- ✅ Message ID format validation (valid, invalid, timestamps)
- ✅ Timestamp validation (max age, clock skew, boundaries)
- ✅ Base validation (missing elements, identifiers)
- ✅ Multiple transaction rejection (2+ transactions)
- ✅ Real-world scenarios (replay attacks, clock drift)
Total PACS.028 Tests: 83 comprehensive tests ✅
Related Documentation
- PACS.008 Payment Initiation API Documentation - How to submit transfers
- ISO 20022 PACS.028 Standard - Official ISO 20022 documentation
- Example PACS.028 Requests - Sample XML files
Support
For questions or issues with the PACS.028 endpoint:
- Check this documentation first
- Review example XML files in
examples/pacs028-requests/ - Verify your message ID format matches SHNET requirements
- Ensure you're using the correct transfer ID from PACS.002 response
- Remember: Only single-transaction queries are supported per request
Updated 6 days ago
