PACS.008 Payment Initiation
ISO 20022 PACS.008 Customer Credit Transfer API documentation for submitting payments via the StrongholdNET network.
PACS.008 Payment Initiation API Documentation
Overview
The PACS.008 endpoint processes ISO 20022 Customer Credit Transfer messages and returns PACS.002 Payment Status Report responses. This endpoint provides standards-compliant payment processing across multiple payment networks.
Endpoint: POST /v1/pacs008/{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/pacs008/shnet
Content-Type: application/xml
SHNET-API-KEY: your-api-key-hereRequest Format (PACS.008)
Minimal PACS.008 Example for SHNET Network
Field Markers:
- [VALIDATION] = Required for format validation to pass
- [TRANSFER] = Required for transfer creation (includes all [VALIDATION] requirements)
- [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.008.001.13">
<!-- [VALIDATION] FIToFICstmrCdtTrf: Root payment element - REQUIRED -->
<FIToFICstmrCdtTrf>
<!-- [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>
<!-- [OPTIONAL] NbOfTxs: Number of transactions (Phase 1: always 1)
Not validated -->
<NbOfTxs>1</NbOfTxs>
</GrpHdr>
<!-- [VALIDATION] CdtTrfTxInf: Credit Transfer Transaction - REQUIRED
Phase 1: Must contain exactly ONE transaction (multiple not supported) -->
<CdtTrfTxInf>
<!-- [OPTIONAL] PmtId: Payment Identification - STRONGLY RECOMMENDED for tracking -->
<PmtId>
<!-- [OPTIONAL] InstrId: Instruction ID - returned in PACS.002 response -->
<InstrId>INSTR-001</InstrId>
<!-- [OPTIONAL] EndToEndId: End-to-end ID - returned in PACS.002 response -->
<EndToEndId>E2E-20241127-001</EndToEndId>
<!-- [OPTIONAL] TxId: Transaction ID -->
<TxId>TXN-001</TxId>
</PmtId>
<!-- [VALIDATION] IntrBkSttlmAmt: Settlement Amount - REQUIRED
[TRANSFER] Ccy attribute: Currency code (ISO 4217) - REQUIRED for transfer
SHNET limits: $0.01 to $10,000
SHNET supports: USD only (converted to SHX token on Stellar) -->
<IntrBkSttlmAmt Ccy="USD">100.00</IntrBkSttlmAmt>
<!-- [TRANSFER] DbtrAcct: Debtor (Source) Account - REQUIRED for transfer creation
This is the ACH source account that will be debited -->
<DbtrAcct>
<Id>
<Othr>
<!-- [TRANSFER] Account number or identifier - REQUIRED -->
<Id>123456789</Id>
</Othr>
</Id>
</DbtrAcct>
<!-- [TRANSFER] CdtrAcct: Creditor (Destination) Account - REQUIRED for transfer creation
This is the Stellar destination that will receive the funds -->
<CdtrAcct>
<Id>
<Othr>
<!-- [TRANSFER] Stellar Public Key (56 characters starting with G) - REQUIRED
Example: GDSTELLARPUBLICKEY123XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->
<Id>GDSTELLARPUBLICKEY123XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Id>
</Othr>
</Id>
<!-- [OPTIONAL] Nm: Stellar memo/reference - Recommended for tracking
Max 28 characters, included in Stellar transaction memo -->
<Nm>Order #12345</Nm>
</CdtrAcct>
</CdtTrfTxInf>
</FIToFICstmrCdtTrf>
</Document>Response Format (PACS.002)
Success Response - Acceptance (HTTP 201)
When a payment is accepted for processing:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<!-- Group Header -->
<GrpHdr>
<MsgId>RESP-1732704600-A1B2C3D4</MsgId>
<CreDtTm>2024-11-27T10:30:00Z</CreDtTm>
</GrpHdr>
<!-- Transaction Information and Status -->
<TxInfAndSts>
<OrgnlEndToEndId>E2E-ACME-INV12345</OrgnlEndToEndId>
<OrgnlInstrId>INSTR-2024-11-27-001</OrgnlInstrId>
<TxSts>ACCP</TxSts>
<StsRsnInf>
<AddtlInf>TransferId: 01939b9d-4f9e-7654-b123-456789abcdef</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: ACCP - Accepted Customer Profile (Payment has been accepted)
Rejection Response - Validation Error (HTTP 400)
When a payment is rejected due to validation errors:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732704601-E1F2G3H4</MsgId>
<CreDtTm>2024-11-27T10:30:01Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>E2E-ACME-INV12345</OrgnlEndToEndId>
<OrgnlInstrId>INSTR-2024-11-27-001</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>AM09</Cd>
</Rsn>
<AddtlInf>Amount 15000 exceeds SHNET maximum of 10000</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Status Code: RJCT - Rejected
Reason Code: AM09 - Wrong Amount
Rejection Response - XML Parsing Error (HTTP 400)
When the 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-1732704602-K1L2M3N4</MsgId>
<CreDtTm>2024-11-27T10:30:02Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>NOTPROVIDED</OrgnlEndToEndId>
<OrgnlInstrId>NOTPROVIDED</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>FF01</Cd>
</Rsn>
<AddtlInf>Invalid XML: Element 'GrpHdr' not found in namespace 'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.13'</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Reason Code: FF01 - Invalid File Format
Rejection Response - Invalid Stellar Account (HTTP 400)
When the Stellar public key format is invalid:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.15">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>RESP-1732704603-P1Q2R3S4</MsgId>
<CreDtTm>2024-11-27T10:30:03Z</CreDtTm>
</GrpHdr>
<TxInfAndSts>
<OrgnlEndToEndId>E2E-ACME-INV12345</OrgnlEndToEndId>
<OrgnlInstrId>INSTR-2024-11-27-001</OrgnlInstrId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn>
<Cd>AC01</Cd>
</Rsn>
<AddtlInf>Invalid Stellar public key format in creditor account. Expected valid Ed25519 public key (56 characters starting with 'G')</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</FIToFIPmtStsRpt>
</Document>Reason Code: AC01 - Incorrect Account Number
Status Codes
Transaction Status Codes (TxSts)
| Code | Name | Description |
|---|---|---|
ACCP | Accepted Customer Profile | Payment accepted for processing |
ACSC | Accepted Settlement Completed | Payment settled successfully |
RJCT | Rejected | Payment rejected |
PDNG | Pending | Payment is pending |
ACSP | Accepted Settlement In Process | Settlement is in progress |
HTTP Status Codes
| HTTP Code | Scenario | PACS.002 Status |
|---|---|---|
| 201 | Payment accepted successfully | ACCP |
| 400 | Validation error, XML parsing error, business logic error | RJCT |
| 401 | Authentication failed (no PACS.002 sent) | N/A |
| 422 | Unexpected processing error | RJCT |
| 500 | Internal server configuration error | RJCT |
Reason Codes (Current Phase 2)
| Code | Name | Description | Example Scenario |
|---|---|---|---|
FF01 | Invalid File Format | XML parsing/schema validation errors | Malformed XML, missing elements |
AM09 | Wrong Amount | Amount validation failed | Exceeds limits, negative amount |
AC01 | Incorrect Account Number | Account/routing number validation failed | Invalid format, account doesn't exist |
NARR | Narrative | Generic reason with custom explanation | Catch-all for various errors |
CUST | Invalid Currency | Currency code validation failed | Unsupported currency |
AG01 | Invalid Agent | BIC/bank identification validation failed | Unknown BIC code |
Reason Codes (Planned for Phase 3)
Amount-Related Codes
AM04- Insufficient FundsAM05- DuplicationAM18- Invalid Amount
Account-Related Codes
AC03- Invalid Creditor Account NumberAC04- Closed Account NumberAC06- Blocked AccountAC13- Invalid Debtor Account Type
Agent-Related Codes
AG02- Invalid Bank Operation CodeAG03- Transaction ForbiddenAGNT- Incorrect Agent
Generic Codes
DUPL- Duplicate PaymentTECH- Technical ProblemUPAY- Undue PaymentRR04- Regulatory ReasonLEGL- Legal Decision
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: 1732675800A3F2B7E156Amount Validation
- Minimum: $0.01
- Maximum: $10,000
- Precision: Up to 2 decimal places
- Validation: Amount must be greater than zero
Currency Validation
- Supported: USD only
- Conversion: All USD transfers are converted to SHX tokens on the Stellar blockchain
- Format: 3-letter currency code (e.g.,
USD)
Required Fields for Validation
Minimum fields to pass validation:
FIToFICstmrCdtTrf- Root elementGrpHdr/MsgId- SHNET format message IDCdtTrfTxInf- Exactly ONE transaction (multiple not supported in Phase 1)IntrBkSttlmAmt- Amount with Ccy attribute- Amount > 0 and within limits
Required Fields for Transfer Creation
Additional fields needed to create a transfer:
DbtrAcct/Id/Othr/Id- Source ACH account numberCdtrAcct/Id/Othr/Id- Destination Stellar public key (56 chars, starts with G)
Optional but recommended:
PmtId/InstrId- Instruction ID (returned in PACS.002)PmtId/EndToEndId- End-to-end ID (returned in PACS.002)CdtrAcct/Nm- Stellar memo (max 28 characters)
NOT Required for SHNET
DbtrAgt- Debtor Agent (only required for FedWire)CdtrAgt- Creditor Agent (only required for FedWire)Dbtr- Debtor party detailsCdtr- Creditor party details
Error Scenarios & Examples
Scenario 1: Missing Required Field
Request: PACS.008 missing <MsgId>
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>FF01</Cd></Rsn>
<AddtlInf>Required field 'MsgId' is missing from GroupHeader</AddtlInf>
</StsRsnInf>Scenario 2: Invalid SHNET Message ID Format
Request: PACS.008 with <MsgId>INVALID-MSG-ID</MsgId> (not in SHNET format)
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>NARR</Cd></Rsn>
<AddtlInf>Invalid SHNET message ID format. Expected: {UnixTimestamp}{Random10Hex} (e.g., 1730103000A3F2B7E156)</AddtlInf>
</StsRsnInf>Scenario 3: Invalid Network
Request: POST /v1/pacs008/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 4: Amount Too Large
Request: PACS.008 with amount exceeding $10,000
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>AM09</Cd></Rsn>
<AddtlInf>Amount 15000 exceeds SHNET maximum of 10000</AddtlInf>
</StsRsnInf>Scenario 5: Invalid Stellar Public Key
Request: PACS.008 with invalid Stellar public key in <CdtrAcct> (e.g., too short, wrong prefix, invalid checksum)
Response (HTTP 400):
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>AC01</Cd></Rsn>
<AddtlInf>Invalid Stellar public key format in creditor account. Expected valid Ed25519 public key (56 characters starting with 'G')</AddtlInf>
</StsRsnInf>Best Practices
Message ID Generation for SHNET
IMPORTANT: SHNET requires a specific message ID format for security and replay protection.
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}`Security:
- Never reuse message IDs (enforced by timestamp + random)
- Messages older than 24 hours are automatically rejected
- Future-dated messages (>5min ahead) are rejected
End-to-End ID
- Should be unique per payment instruction
- Use for reconciliation and tracking
- Format:
E2E-{organization}-{reference}
Error Handling
- Always check HTTP status code first
- Parse PACS.002 response for detailed reason codes
- Log
OrgnlEndToEndIdfor correlation - Implement retry logic for transient errors (500, 503)
Testing
- Validate XML locally before sending
- Test with small amounts first
- Use sandbox environment for integration
- Keep test message IDs unique
- Test all error scenarios
Updated 19 days ago
