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/xml or text/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-here

Request 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)

CodeNameDescriptionTransfer State
ACSPAccepted Settlement In ProcessTransfer is created or being processedCreated, Processing
ACSCAccepted Settlement CompletedTransfer completed successfullyCompleted
RJCTRejectedTransfer failed or not foundFailed, Not Found

HTTP Status Codes

HTTP CodeScenarioPACS.002 Status
200Status report returned successfullyACSP, ACSC, RJCT
400Invalid request format, missing transfer IDRJCT
401Authentication failed (no PACS.002 sent)N/A
404Transfer not foundRJCT
500Internal server errorRJCT

Transfer Status Mapping

Internal StatusISO 20022 CodeDescriptionAdditional Information
CreatedACSPAccepted Settlement In ProcessTransfer queued, not yet started
ProcessingACSPAccepted Settlement In ProcessTransfer actively processing
CompletedACSCAccepted Settlement CompletedIncludes transaction hash
FailedRJCTRejectedIncludes error code and reason

Reason Codes

CodeNameDescriptionExample Scenario
FF01Invalid File FormatXML parsing/schema validation errorsMalformed XML, missing elements
AC01Incorrect Account NumberTransfer ID not found or invalidNon-existent transfer ID
NARRNarrativeGeneric reason with custom explanationMissing 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: 1732675800A3F2B7E156

Required Fields for Validation

Minimum fields to pass validation:

  1. FIToFIPmtStsReq - Root element
  2. GrpHdr/MsgId - SHNET format message ID
  3. TxInf/OrgnlInstrId OR TxInf/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 TxInf element per PACS.028 request
  • Not Supported: Multiple TxInf elements 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.xml

Step 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.xml

pacs028_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.

  1. Extract from PACS.002: Parse the TransferId: {uuid} from AddtlInf
  2. Store Securely: Save the UUID in your database linked to the payment
  3. Use for Queries: Include in OrgnlInstrId field 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

  1. Don't Poll Too Frequently: Wait at least 5-10 seconds between status checks
  2. Exponential Backoff: Increase wait time if transfer is still processing
  3. Set Maximum Retries: Stop polling after a reasonable timeout (e.g., 5 minutes)
  4. 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

  1. Submit Test Transfer First: Use PACS.008 to create a transfer
  2. Store Transfer ID: Save the ID from the acceptance response
  3. Query Immediately: Test status query while transfer is still processing
  4. Query After Completion: Verify completed transfers show correct status
  5. 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:

FieldExamplePurpose
MessageTypepacs.028Identifies message as status query
MessageId1732675800A3F2B7E156Unique message identifier
OriginalInstructionIdtransfer_uuidTransfer ID being queried
OriginalEndToEndIdAlternative IDAlternative transfer ID (if provided)
OriginalMessageIdOriginal PACS.008 IDMessage being queried (if provided via OrgnlGrpInf)
RawXmlContentFull XMLComplete request for debugging
OrganizationIdYour org IDOrganization making the query
ApiEnvironmentSandbox/ProductionEnvironment context
NetworkShnetPayment network
CreatedAtTimestampWhen 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:

  1. Real-time use case - Most queries are for individual transfers
  2. Simpler implementation - Easier to maintain and optimize
  3. Industry standard - Matches SWIFT, FedNow approaches
  4. 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
done

Option 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


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