App - transact V2 - Validation and normalization
What is this about?
We’re rolling out stricter validation and normalization across several safe-transact API endpoints.
This change is intended to make asset, address, identifier, and relationship inputs more consistent and predictable, while reducing cases where malformed data is accepted.
How is this affecting me?
If you are integrating with these APIs, or already have an integration running, this change may affect you in two ways:
- Validation: you will receive a
400error if you submit an invalid payload according to the new validation requirements. - Normalization: the API will return normalized values. For
GETendpoints, data returned by the API may be normalized according to the logic described below.
Affected endpoints
POST /entities/{entityDID}/txPOST /entities/{entityDID}/tx/{transferId}/settleGET /entities/{entityDID}/tx/matchPOST /entities/{entityDID}/tx/{transferId}/agentsPOST /entities/{entityDID}/tx/{transferId}/agents/replacePOST /entities/{entityDID}/relationshipsPATCH /entities/{entityDID}/relationshipsGET /entities/{entityDID}/relationshipsDELETE /entities/{entityDID}/relationshipsPOST /entities/{entityDID}/transfers/{transferId}/appendPOST /entities/{entityDID}/delegateTokenPOST /entity/{entityDID}/address-ownership/discover
Validation rules
DID fields must match /^did:[a-z0-9]+:.+/
- ✅
did:key:z6mkh... - ❌
user_123
IRI-style fields affect fields such as @id and delegateId must match /^[a-zA-Z][a-zA-Z0-9+.-]*:.+$/
- ✅
https://example.com/id/123 - ✅
urn:uuid:123e4567-e89b-12d3-a456-426614174000 - ❌
12345
Address validation checks that addresses are valid for the relevant chain when chain context is available.
- ✅ Plain address, CAIP-10, and
did:pkhinputs are accepted where supported - ✅ Existing
did:pkhvalues are checked for consistency with the provided asset chain - ❌ Invalid address format for the given chain returns
400 - ❌ Chain/address mismatches return
400
Examples:
- ✅
0xAbC123...with an EVM asset - ✅
did:pkh:eip155:1:0xabcd1234... - ❌ BTC address provided with an EVM asset
- ❌ Malformed
did:pkhvalue
Transaction hash validation checks settlement and transfer hash inputs for valid structure.
- ✅ Raw chain hashes may be accepted and normalized where supported
- ✅ CAIP-220 formatted values are accepted
- ❌ Invalid or malformed transaction hash values return
400
Examples:
- ✅
0x4e3f... - ✅
eip155:1:tx/0x4e3f... - ❌
not-a-hash - ❌
eip155:1:tx/
Asset validation checks that asset values are valid CAIP-19 identifiers and that the chain can be resolved.
- ✅ Supported CAIP-19 asset values are accepted, ticker symbol is also accepted, learn more here
- ❌ Unknown or unresolvable asset values return
400
Examples:
- ✅
eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 - ❌ Invalid CAIP-19 asset format
- ❌ Asset with an unresolvable chain
Memo tag validation checks memo or destination-tag values extracted from CAIP-10 addresses and validates them per chain.
- ✅ Chain-specific memo formats are accepted
- ❌ Invalid memo format returns
400 - ❌ Conflicting memo values return
400
Examples:
- ✅ XRP address with numeric destination tag
- ❌ XRP address with non-numeric destination tag
- ❌ Conflicting memo tag values in the same request
Array-typed fields enforce schema shape, per-field length checks, and maxItems: 25
Free-form string fields, including IVMS-related values and txAppend payload fields, enforce length limits of 2–255 characters
Endpoint validation matrix
| Endpoint | DID regex | IRI regex | Address validation | Tx hash validation | Asset validation | Memo tag validation | Unknown address 2–255 | Array validation |
|---|---|---|---|---|---|---|---|---|
POST /entities/{entityDID}/tx | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No |
POST /entities/{entityDID}/tx/{transferId}/settle | No | No | No | Yes | No | No | No | No |
GET /entities/{entityDID}/tx/match | No | No | Yes | Yes | Yes | Yes | Yes | No |
POST /entities/{entityDID}/tx/{transferId}/agents | Yes | Yes | Yes | No | Yes | Yes | Yes | No |
POST /entities/{entityDID}/tx/{transferId}/agents/replace | Yes | Yes | Yes | No | Yes | Yes | Yes | No |
POST /entities/{entityDID}/relationships | Yes | No | Yes | No | Yes | No | No | No |
PATCH /entities/{entityDID}/relationships | Yes | No | Yes | No | Yes | No | No | No |
GET /entities/{entityDID}/relationships | Yes | No | Yes | No | Yes | No | No | No |
DELETE /entities/{entityDID}/relationships | Yes | No | Yes | No | Yes | No | No | No |
POST /entities/{entityDID}/transfers/{transferId}/append | No | Yes | No | No | No | No | No | Yes |
POST /entities/{entityDID}/delegateToken | Yes | Yes | No | No | No | No | No | No |
POST /entity/{entityDID}/address-ownership/discover | Yes | No | Yes | No | Yes | Yes | Yes | No |
Normalization
EVM addresses are normalized to lowercase on write, with case-insensitive lookup on read.
- Input:
0xABCD1234... - Stored/compared as:
0xabcd1234...
Address inputs are normalized to did:pkh format where applicable.
- Input: plain address / CAIP-10 /
did:pkh - Normalized form:
did:pkh:<namespace>:<reference>:<address>
Transaction hashes are normalized to CAIP-220 format where applicable.
- Input: raw chain hash
- Normalized form:
<namespace>:<reference>:tx/<hash>
