Wallet Integration Guide
This guide walks you through the complete integration workflow for creating and managing Web3 wallets using the Freeq API.
The Asynchronous Integration Flow (Recommended)
The integration primarily involves two API endpoints that you will call from your backend service during your user authentication flow.
Step 1: User Sign-Up / First-Time Login
When a new user signs up or an existing user logs in for the first time after this integration is live, call the /createasync endpoint. This initiates the wallet creation process.
Endpoint: POST https://api.testnet.superfreeq.com/api/v1/wallets/createasync
Headers
| Header | Description |
|---|---|
Authorization | Bearer <Your User's JWT> |
Content-Type | application/json |
Request Body
{
// Your mandatory project_key
"key": "YOUR_PROJECT_KEY_HERE",
// Optional: Any custom data you want echoed back in the webhook payload
"any_other_tokens": "example-unique-identifier-from-your-system"
}
Parameters:
key: Your mandatoryproject_keyany_other_tokens: Custom value (e.g., a user ID or session token from your system). If you use webhooks, these values will be echoed back to you, helping you associate the incoming wallet data with the correct user in your database.
Example Request
curl -X POST \
https://api.testnet.superfreeq.com/api/v1/wallets/createasync \
-H 'Authorization: Bearer eyJhbGciOiJSUzI1Ni...' \
-H 'Content-Type: application/json' \
-d '{
"key": "YOUR_PROJECT_KEY_HERE",
"token": "user_12345_session_abcde"
}'
Responses
202 Accepted: Success! The request has been accepted, and wallet creation is in progress401 Unauthorized: The provided JWT is invalid or expired. See JWT requirements400 Bad Request: The request is missing required parameters (like theproject_key) or is malformed
Flow Diagram: First-Time User
Step 2: Subsequent User Logins
For every subsequent login for a user who already has a wallet, call the /signin endpoint. This retrieves their existing wallet information.
Endpoint: POST https://api.testnet.superfreeq.com/api/v1/signin
Headers & Request Body: The headers and request body are identical to the /createasync endpoint.
Example Request
curl -X POST \
https://api.testnet.superfreeq.com/api/v1/signin \
-H 'Authorization: Bearer eyJhbGciOiJSUzI1Ni...' \
-H 'Content-Type: application/json' \
-d '{
"key": "YOUR_PROJECT_KEY_HERE"
}'
Responses
200 OK: Success! The response body will contain the user's wallet information401 Unauthorized: The provided JWT is invalid or expired400 Bad Request: The request is malformed
Flow Diagram: Returning User
Calling the /signin endpoint also serves another purpose. If you are using webhooks and a previous webhook notification failed, this call will trigger our system to retry sending that failed notification.
The Synchronous Integration Flow
For synchronous account creation, simply use the /signin endpoint for all users. Similar to /createasync, the /signin endpoint will create a user wallet if it does not already exist.
This approach provides immediate wallet details in the response but may have slightly longer response times for first-time users.
Sample Implementation
Here's a Node.js example using axios to illustrate how you might call the API from your backend:
// This function would be called within your user authentication logic
async function provisionFreeqWallet(userJwt, projectKey, userId) {
const FREEQ_API_URL = 'https://api.testnet.superfreeq.com/api/v1/wallets/createasync';
try {
const response = await axios.post(
FREEQ_API_URL,
{
key: projectKey,
// You can add a custom token here if you're using webhooks
token: `user-id-${userId}`
},
{
headers: {
'Authorization': `Bearer ${userJwt}`,
'Content-Type': 'application/json',
},
}
);
if (response.status === 202) {
console.log('Successfully requested wallet creation for the user.');
}
} catch (error) {
// Handle potential errors, e.g., a 401 due to an invalid token
console.error('Error provisioning Freeq wallet:', error.response?.data || error.message);
}
}
// Example usage:
const userJwt = "eyJhbGciOiJSUzI1Ni...";
const projectKey = "your-project-key-goes-here";
const userId = "user-12345";
provisionFreeqWallet(userJwt, projectKey, userId);
Complete Integration Example
// Complete user authentication flow with Freeq integration
async function handleUserLogin(email, password) {
try {
// 1. Authenticate user with your existing system
const user = await authenticateUser(email, password);
if (!user) {
throw new Error('Invalid credentials');
}
// 2. Generate JWT for the user
const userJwt = generateJWT(user);
// 3. Check if this is a first-time login (after Freeq integration)
const isFirstTimeAfterIntegration = !user.walletAddress;
if (isFirstTimeAfterIntegration) {
// First-time user: Create wallet asynchronously
await provisionFreeqWallet(userJwt, PROJECT_KEY, user.id);
// Wallet creation is in progress, will be available via webhook
return {
user,
walletStatus: 'pending',
message: 'Wallet is being created...'
};
} else {
// Returning user: Get existing wallet info
const walletInfo = await getExistingWallet(userJwt, PROJECT_KEY);
return {
user,
walletInfo,
walletStatus: 'ready'
};
}
} catch (error) {
console.error('Login error:', error);
throw error;
}
}
async function getExistingWallet(userJwt, projectKey) {
const response = await axios.post(
'https://api.testnet.superfreeq.com/api/v1/signin',
{ key: projectKey },
{
headers: {
'Authorization': `Bearer ${userJwt}`,
'Content-Type': 'application/json',
},
}
);
return response.data;
}
Receiving Wallet Data: Webhooks
While you can always get wallet information by calling /signin, using webhooks provides a more robust, real-time solution. As soon as a wallet is created, our system will push the details to an endpoint you provide.
Webhook Setup
- Provide your public webhook URL to the Freeq team during setup
- Ensure your endpoint can accept
POSTrequests with a JSON body
Webhook Payload
When a wallet is created, we will send a POST request to your endpoint with the following payload:
{
"walletId": 36,
"walletAddress": "0xc3c419d92B3129a4FF4b5a3219A05314072EFF67",
"emailAddress": "user@example.com",
"token": "user_12345_session_abcde" // The optional token you passed in the initial request
}
Webhook Implementation Example
// Express.js webhook handler
app.post('/webhooks/freeq', express.json(), (req, res) => {
try {
const { walletId, walletAddress, emailAddress, token } = req.body;
// Validate the webhook payload
if (!walletAddress || !emailAddress) {
return res.status(400).json({ error: 'Invalid webhook payload' });
}
// Update your database with the wallet information
await updateUserWallet(emailAddress, {
walletId,
walletAddress,
customToken: token
});
// Acknowledge successful receipt
res.status(200).json({ received: true });
console.log(`Wallet created for ${emailAddress}: ${walletAddress}`);
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
async function updateUserWallet(email, walletData) {
// Update your user record in the database
await User.updateOne(
{ email },
{
walletAddress: walletData.walletAddress,
walletId: walletData.walletId,
walletCreatedAt: new Date()
}
);
}
Responding to Webhooks
To acknowledge that you have successfully received the webhook, your endpoint must return a 2xx HTTP status code (e.g., 200 OK or 204 No Content).
Any other response code (e.g., 4xx or 5xx) will be considered a failure.
Automatic Retries
If we receive a non-2xx response from your webhook endpoint, we will mark the delivery as failed. Our system will automatically attempt to send it again the next time that same user logs in (i.e., the next time you call /signin for that user).
Key Integration Points
Idempotent Operations
Our system is idempotent based on the user's identity (email). If a wallet already exists for that user, the system will simply acknowledge the request and no duplicate wallet will be created. You can safely call /createasync on first login and /signin on all subsequent logins.
Error Handling Best Practices
async function handleFreeqRequest(userJwt, projectKey, isFirstTime = false) {
const endpoint = isFirstTime ? '/createasync' : '/signin';
try {
const response = await axios.post(
`https://api.testnet.superfreeq.com/api/v1/wallets${endpoint}`,
{ key: projectKey },
{
headers: {
'Authorization': `Bearer ${userJwt}`,
'Content-Type': 'application/json',
},
timeout: 10000, // 10 second timeout
}
);
return response.data;
} catch (error) {
if (error.response) {
// Server responded with error status
switch (error.response.status) {
case 401:
console.error('JWT authentication failed:', error.response.data);
throw new Error('Authentication failed. Please check JWT configuration.');
case 400:
console.error('Bad request:', error.response.data);
throw new Error('Invalid request parameters.');
case 500:
console.error('Server error:', error.response.data);
throw new Error('Freeq API temporarily unavailable.');
default:
console.error('Unexpected error:', error.response.data);
throw new Error('Unexpected API error.');
}
} else if (error.request) {
// Network error
console.error('Network error:', error.message);
throw new Error('Unable to connect to Freeq API.');
} else {
// Other error
console.error('Request setup error:', error.message);
throw new Error('Invalid request configuration.');
}
}
}
Next Steps
Now that you understand the integration workflow:
- Complete the Prerequisites Checklist to ensure your setup is ready
- Review Authentication Requirements for detailed JWT specifications
- Explore the Complete API Reference for additional features and endpoints
- Set up Webhook Integration for real-time notifications
If you encounter issues, check our Troubleshooting Guide for common solutions.
Use the interactive Swagger Documentation to test your JWT authentication and API calls before implementing in your application.