Sign with Privy
This guide shows how to use Privy embedded wallets to sign Due transfer intents via REST API.
Prerequisites
- Privy App ID and Privy App Secret - found in your Privy application settings (App settings > Basics)
- Due Platform API key - contact Due Network team for access
- A Due account with a linked Privy wallet
For more information:
Signing Flow
When you create a crypto → fiat transfer in Due, you need to sign the transfer intent before funds can be moved. This involves:
- Creating a transfer intent
- Signing each signable object via Privy API
- Submitting the signed intent back to Due
Step 1: Create a Transfer Intent
First, create a transfer intent for your existing transfer:
curl --request POST \
--url https://api.due.network/v1/transfers/{transfer_id}/transfer_intent \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Due-Account-Id: <ACCOUNT_ID>'Response:
{
"id": "ti_24QbulYAT9nfjU",
"sender": "evm:0xcF5AaaBe14Ba42d9D765C8f2b9099c3b69a25321",
"signables": [
{
"payload": {
"kind": "typed_data",
"value": {
"types": {
"Permit": [
{"name": "owner", "type": "address"},
{"name": "spender", "type": "address"},
{"name": "value", "type": "uint256"},
{"name": "nonce", "type": "uint256"},
{"name": "deadline", "type": "uint256"}
]
},
"primaryType": "Permit",
"domain": {
"name": "USDC",
"version": "1",
"chainId": "2000",
"verifyingContract": "0xA52B297943dd6F3D5fFb41F50040BB2Bc6272F06"
},
"message": {
"owner": "0xcF5AaaBe14Ba42d9D765C8f2b9099c3b69a25321",
"spender": "0xC2E594095801A382894b761b511B44775e1716a6",
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "0",
"deadline": "1759424402"
}
}
},
"hash": "0x7ab1ccbb88a8cf030de759744c4ac249f06b2512242e5624058bcda99daf2576"
},
{
"payload": {
"kind": "typed_data",
"value": {
"types": {
"PayoutIntent": [
{"name": "sender", "type": "address"},
{"name": "relay", "type": "address"},
{"name": "calls", "type": "bytes[]"},
{"name": "nonce", "type": "bytes32"},
{"name": "deadline", "type": "uint256"}
]
},
"primaryType": "PayoutIntent",
"domain": {
"name": "DuePayout",
"version": "1",
"chainId": "2000",
"verifyingContract": "0xC2E594095801A382894b761b511B44775e1716a6"
},
"message": {
"sender": "0xcF5AaaBe14Ba42d9D765C8f2b9099c3b69a25321",
"relay": "0xBADDA95F65be56Dc4cD737E865a2d35F0B672BAD",
"calls": ["0xb9b8bc50..."],
"nonce": "0xae7813992f91fd41c18bed8734c8d1914d13adad6bfb80f656869813cbc170ad",
"deadline": "1759424402"
}
}
},
"hash": "0x51dc7acb50075ea1ac934409c5d40e52b1744df19922894d35ba261c86777f95"
}
],
"expiresAt": "2025-10-02T17:00:02.25776447Z"
}The response contains a signables array - typically two objects: Permit (token approval) and PayoutIntent (the actual transfer).
Important: Transfer intents expire (see
expiresAtfield). Complete signing before expiration.
Step 2: Sign Each Signable with Privy
For each object in the signables array, use Privy's eth_signTypedData_v4 method to generate a signature.
Example: Signing the Permit
curl --request POST \
--url https://api.privy.io/v1/wallets/<wallet_id>/rpc \
-u "<your-privy-app-id>:<your-privy-app-secret>" \
--header 'privy-app-id: <your-app-id>' \
--header 'Content-Type: application/json' \
--data '{
"method": "eth_signTypedData_v4",
"params": {
"typed_data": {
"domain": {
"name": "USDC",
"version": "1",
"chainId": "2000",
"verifyingContract": "0xA52B297943dd6F3D5fFb41F50040BB2Bc6272F06"
},
"types": {
"Permit": [
{"name": "owner", "type": "address"},
{"name": "spender", "type": "address"},
{"name": "value", "type": "uint256"},
{"name": "nonce", "type": "uint256"},
{"name": "deadline", "type": "uint256"}
]
},
"primary_type": "Permit",
"message": {
"owner": "0xcF5AaaBe14Ba42d9D765C8f2b9099c3b69a25321",
"spender": "0xC2E594095801A382894b761b511B44775e1716a6",
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "0",
"deadline": "1759424402"
}
}
}
}'Response:
{
"method": "eth_signTypedData_v4",
"data": {
"signature": "0xd99802ab7a14b535ad0bf9c69a7cfd862797a5f3b48270db20fdbd7a170a433e79970506944a3289e1ee2c7d0324b6097d9f67c51816792dbbac0f8c2c8af4b11b",
"encoding": "hex"
}
}Repeat this process for the PayoutIntent signable, using its respective domain, types, and message values from the transfer intent response.
For more details, see Privy: Sign Typed Data.
Step 3: Submit the Signed Intent
After obtaining signatures for all signables, submit the complete transfer intent with signatures to Due:
curl --request POST \
--url https://api.due.network/v1/transfer_intents/submit \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Due-Account-Id: <ACCOUNT_ID>' \
--data '{
"id": "ti_24QbulYAT9nfjU",
"ownerId": "acct_DkRHlTg5q8VZM6Gn",
"sender": "evm:0xcF5AaaBe14Ba42d9D765C8f2b9099c3b69a25321",
"amountIn": "1177.29598",
"to": {
"evm:0xbad09Fb9781D9D57E1423231AC51f9bb9e0CABAD": "1177.29598"
},
"tokenIn": "USDC",
"tokenOut": "USDC",
"networkIdIn": "base",
"networkIdOut": "base",
"signables": [
{
"payload": {
"kind": "typed_data",
"value": { ... }
},
"hash": "0x7ab1ccbb88a8cf030de759744c4ac249f06b2512242e5624058bcda99daf2576",
"signature": "0xd99802ab7a14b535ad0bf9c69a7cfd862797a5f3b48270db20fdbd7a170a433e..."
},
{
"payload": {
"kind": "typed_data",
"value": { ... }
},
"hash": "0x51dc7acb50075ea1ac934409c5d40e52b1744df19922894d35ba261c86777f95",
"signature": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456..."
}
],
"nonce": "0xae7813992f91fd41c18bed8734c8d1914d13adad6bfb80f656869813cbc170ad",
"hash": "0x51dc7acb50075ea1ac934409c5d40e52b1744df19922894d35ba261c86777f95",
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"expiresAt": "2025-10-02T17:00:02.25776447Z",
"createdAt": "2025-10-02T16:45:02.302661636Z",
"reference": "tf_2ghR6HgkRHTQB8:deposit"
}'Response:
{
"id": "ti_24QbulYAT9nfjU",
"status": "payment_submitted",
"txHashIn": "0x1234567890abcdef...",
"createdAt": "2025-10-02T16:45:02Z"
}The transfer is now submitted and will be processed by Due.
Alternative: Funding Address
For a simpler approach that doesn't require signing, you can use a funding address instead. See Due: Stablecoin to Fiat Transfers for details.
Additional Resources
Updated about 19 hours ago