Project Management
Learn how to manage projects, retrieve project information, and understand project-wallet relationships.
What is a Project?​
A project represents a business entity or service in the Paysera system. Each project:
- Has an owner (user or company)
- Has a default wallet for receiving payments
- Can be accessed by multiple clients
- Organizes related resources and permissions
Get Project by ID​
Retrieve detailed information about a specific project.
Request
GET /rest/v1/project/{projectId}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | integer | ✅ Yes | ID of the project |
Response
{
"id": 1221,
"title": "My E-Commerce Store",
"description": "Online payment processing for my store",
"wallet_id": 2112,
"owner_display_name": "John's Company Ltd"
}
View Response Fields
| Field | Type | Always Present | Description |
|---|---|---|---|
id | integer | ✅ Yes | Project ID |
title | string | ✅ Yes | Project title |
description | string | ⬜ Optional | Project description |
wallet_id | integer | ⬜ Optional | Associated wallet ID |
owner_display_name | string | ⬜ Optional | Owner's display name |
Example
async function getProjectInfo(projectId) {
const project = await api.getProject(projectId);
console.log(`Project: ${project.title}`);
console.log(`Owner: ${project.owner_display_name}`);
console.log(`Wallet ID: ${project.wallet_id}`);
return project;
}
// Usage
const project = await getProjectInfo(1221);
Get User's Administered Projects​
Retrieve all projects that a user can administer.
Request
GET /rest/v1/user/{userId}/projects
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | integer or me | ✅ Yes | User ID or me for current user |
When using access tokens, you can use me instead of the user ID to get projects for the authenticated user.
Required Scope: projects - This endpoint requires the projects OAuth scope.
Response: Array of project objects
[
{
"id": 1221,
"title": "My E-Commerce Store",
"description": "Online payment processing",
"wallet_id": 2112,
"owner_display_name": "John's Company Ltd"
},
{
"id": 1222,
"title": "My Second Project",
"wallet_id": 2113,
"owner_display_name": "John's Company Ltd"
}
]
View Example
async function getUserProjects(userId = 'me') {
const projects = await api.getUserProjects(userId);
console.log(`Found ${projects.length} projects:`);
projects.forEach(p => {
console.log(`- ${p.title} (ID: ${p.id})`);
});
return projects;
}
// Usage with access token
const myProjects = await getUserProjects('me');
// Usage with specific user ID
const userProjects = await getUserProjects(1234);
Project-Wallet Relationship​
Understanding how projects and wallets work together.
Key Points
- Each project has a default wallet for receiving payments
- Wallet belongs to the project owner (user or company)
- Multiple projects can share the same wallet (if they have the same owner)
- Clients can specify project using
project_idparameter
Diagram
Example Scenario:
- Company owns Wallet 1 and Wallet 2
- Project A and Project B use Wallet 1
- Project C uses Wallet 2
- Each project can have multiple clients
Using project_id Parameter​
When a client can access multiple projects, specify which project using the project_id parameter.
When to Use
- ✅ Client manages multiple projects
- ✅ Access token has
projectsscope - ✅ Need to specify target project for operation
How to Pass project_id
With MAC Authentication
Include in ext field:
GET /rest/v1/wallet/14471/balance HTTP/1.1
Host: wallet.paysera.com
Authorization: MAC id="wkVd93h2uS",
ts="1343811600",
nonce="nQnNaSNyubfPErjRO55yaaEYo9YZfKHN",
mac="EOhN6gBf49tR2KxMflaaiN7bBVGDhfG6co8gcSBLyiQ=",
ext="project_id=1221"
With SSL Certificate
Use custom header:
GET /rest/v1/wallet/14471/balance HTTP/1.1
Host: wallet.paysera.com
Wallet-Api-Project-Id: 1221
Implementation Example
class MultiProjectClient {
constructor(credentials) {
this.client = new PayseraClient(credentials);
this.projects = [];
}
async initialize() {
// Load all available projects
this.projects = await this.client.getUserProjects('me');
console.log(`Loaded ${this.projects.length} projects`);
}
async getWalletBalance(walletId, projectId) {
// Make request with project_id
return await this.client.request('/wallet/' + walletId + '/balance', {
headers: {
'Wallet-Api-Project-Id': projectId
}
});
}
async getAllProjectBalances() {
const balances = [];
for (const project of this.projects) {
try {
const balance = await this.getWalletBalance(
project.wallet_id,
project.id
);
balances.push({
project: project.title,
wallet_id: project.wallet_id,
balance: balance
});
} catch (error) {
console.error(`Error for project ${project.id}:`, error);
}
}
return balances;
}
}
// Usage
const client = new MultiProjectClient(credentials);
await client.initialize();
const balances = await client.getAllProjectBalances();
balances.forEach(b => {
console.log(`${b.project}: ${b.balance.amount} ${b.balance.currency}`);
});
Advanced Topics​
Project Setup Workflow
For New Integration
-
Contact Paysera Support
- Describe your use case
- Provide business details
- Request project creation
-
Receive Project Credentials
- Project ID
- Client credentials
- Wallet information
-
Configure Your Application
const config = {
projectId: 1221,
clientId: 'your_client_id',
macKey: 'your_mac_key',
walletId: 2112
}; -
Test Thoroughly
- Test with small amounts
- Test all operations
- Verify payment flows
-
Monitor & Scale
- Monitor operations
- Gradually increase volumes
- Track performance
Best Practice 1: Cache Project Information
class ProjectCache {
constructor(api, ttl = 3600000) { // 1 hour default
this.api = api;
this.ttl = ttl;
this.cache = new Map();
}
async getProject(projectId) {
const cached = this.cache.get(projectId);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const project = await this.api.getProject(projectId);
this.cache.set(projectId, {
data: project,
timestamp: Date.now()
});
return project;
}
clearCache() {
this.cache.clear();
}
}
// Usage
const cache = new ProjectCache(api);
const project = await cache.getProject(1221); // Fetches from API
const sameProject = await cache.getProject(1221); // Returns from cache
Best Practice 2: Handle Multiple Projects
async function selectProject(projects, preferredId = null) {
if (projects.length === 0) {
throw new Error('No projects available');
}
if (projects.length === 1) {
return projects[0];
}
// Try to use preferred project
if (preferredId) {
const preferred = projects.find(p => p.id === preferredId);
if (preferred) return preferred;
}
// Or show selection UI
return await showProjectSelector(projects);
}
Best Practice 3: Validate Project Access
async function ensureProjectAccess(projectId) {
const projects = await api.getUserProjects('me');
const hasAccess = projects.some(p => p.id === projectId);
if (!hasAccess) {
throw new Error(
`No access to project ${projectId}. ` +
`Available projects: ${projects.map(p => p.id).join(', ')}`
);
}
}
// Before using project
await ensureProjectAccess(1221);
await api.createPayment({ project_id: 1221, ... });
Best Practice 4: Store Configuration
// config.json
{
"production": {
"project_id": 1221,
"wallet_id": 2112,
"client_id": "your_client_id"
}
}
// Load configuration
const config = require('./config.json').production;
const client = new PayseraClient({
clientId: config.client_id,
projectId: config.project_id
});
Wallet API operates in production environment only. Store your production credentials securely.
Common Scenarios
Scenario 1: Single Project Integration
Use Case: E-commerce store with one payment project
// Simple setup - hardcode project ID
const PROJECT_ID = 1221;
async function createPayment(orderData) {
return await api.createTransaction({
project_id: PROJECT_ID,
payments: [/* ... */]
});
}
Scenario 2: Multi-Project Dashboard
Use Case: Admin dashboard managing multiple projects
class ProjectDashboard {
async loadProjects() {
this.projects = await api.getUserProjects('me');
}
async getProjectStats(projectId) {
const stats = await api.request('/stats', {
headers: { 'Wallet-Api-Project-Id': projectId }
});
return {
project: this.projects.find(p => p.id === projectId),
stats: stats
};
}
async getAllStats() {
return await Promise.all(
this.projects.map(p => this.getProjectStats(p.id))
);
}
}
Scenario 3: Project Switching
Use Case: App that lets users switch between projects
class ProjectSwitcher {
constructor() {
this.currentProject = null;
}
async switchProject(projectId) {
const projects = await api.getUserProjects('me');
const project = projects.find(p => p.id === projectId);
if (!project) {
throw new Error(`Project ${projectId} not found`);
}
this.currentProject = project;
this.updateUI(project);
await storage.set('selectedProject', projectId);
}
getCurrentProjectId() {
return this.currentProject?.id;
}
}
Troubleshooting
Issue: "Project not found"
Cause: Invalid project ID or no access
Solution:
try {
const project = await api.getProject(projectId);
} catch (error) {
if (error.code === 'not_found') {
console.error('Project not found. Check project ID.');
const available = await api.getUserProjects('me');
console.log('Available projects:', available.map(p => p.id));
}
}
Issue: "Forbidden" when accessing project
Cause: Client doesn't have permission for this project
Solution:
// Check if project_id matches client's project
const clientInfo = await api.getClient();
const projects = await api.getUserProjects('me');
console.log('Client projects:', projects.map(p => p.id));
Issue: Multiple projects, unclear which to use
Cause: No project_id specified
Solution:
// Always specify project_id when managing multiple projects
await api.createPayment({
project_id: selectedProjectId, // Always include!
payments: [/* ... */]
});
Next Steps​
- Location Services - Physical locations and services
- Client Management - Client types and permissions
- Payments - Payment processing
- Authentication - Setup authentication