Memeputer

Best Practices

Tips for building reliable, user-friendly X402 resources.

Reliability

Handle Failures Gracefully

try {
  const result = await processRequest(input);
  return { success: true, data: result };
} catch (error) {
  console.error('Processing error:', error);
  return {
    state: 'failed',
    error: 'Processing failed. Please try again.',
    code: 'processing_error'
  };
}

Set Reasonable Timeouts

Don't let operations run forever:

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);

try {
  const result = await fetch(url, { signal: controller.signal });
  clearTimeout(timeout);
  return result;
} catch (error) {
  if (error.name === 'AbortError') {
    return { state: 'failed', error: 'Request timed out', code: 'timeout' };
  }
  throw error;
}

Implement Idempotency

Allow safe retries by using idempotency keys:

app.post('/generate', async (req, res) => {
  const idempotencyKey = req.headers['x-idempotency-key'];
  
  if (idempotencyKey) {
    const existing = await db.jobs.findByIdempotencyKey(idempotencyKey);
    if (existing) {
      return res.json({ jobId: existing.id, statusUrl: ... });
    }
  }
  
  // Create new job...
});

User Experience

Provide Helpful Descriptions

{
  "prompt": {
    "type": "string",
    "required": true,
    "description": "Describe the image you want. Be specific about style, colors, and composition."
  }
}

Use Sensible Defaults

{
  "quality": {
    "type": "string",
    "enum": ["draft", "standard", "high"],
    "default": "standard",
    "description": "Higher quality = longer generation time"
  }
}

Show Progress for Long Operations

// Update progress during processing
async function processWithProgress(jobId, steps) {
  for (let i = 0; i < steps.length; i++) {
    await db.jobs.update(jobId, {
      progress: Math.floor((i / steps.length) * 100)
    });
    await steps[i]();
  }
}

Performance

Cache When Possible

const cache = new Map();

app.get('/status/:jobId', async (req, res) => {
  const cached = cache.get(req.params.jobId);
  if (cached && cached.state === 'succeeded') {
    return res.json(cached);
  }
  
  const result = await db.jobs.findById(req.params.jobId);
  if (result.state === 'succeeded') {
    cache.set(req.params.jobId, result);
  }
  return res.json(result);
});

Clean Up Old Data

// Run daily cleanup
async function cleanupOldJobs() {
  const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
  await db.jobs.deleteWhere({ createdAt: { lt: cutoff } });
}

Security

Validate All Inputs

import { z } from 'zod';

const inputSchema = z.object({
  prompt: z.string().min(1).max(1000),
  style: z.enum(['realistic', 'anime', 'cartoon']).optional(),
});

app.post('/generate', async (req, res) => {
  const parsed = inputSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({
      error: 'Invalid input',
      details: parsed.error.issues
    });
  }
  // Use parsed.data...
});

Sanitize Outputs

Don't expose internal details in error messages:

// Bad
return { error: `Database error: ${error.message}` };

// Good
console.error('Database error:', error);
return { error: 'An error occurred. Please try again.', code: 'internal_error' };

Pricing

Set Fair Prices

Consider:

  • Your compute costs
  • API costs (OpenAI, etc.)
  • Storage costs
  • Fair margin

Be Transparent

Include pricing in your 402 response:

{
  "maxAmountRequired": "100000",
  "extra": {
    "pricing": {
      "amount": 0.10,
      "currency": "USDC",
      "description": "Per image generation"
    }
  }
}

Monitoring

Log Important Events

console.log(`[${jobId}] Job started`, { input: sanitizedInput });
console.log(`[${jobId}] Job completed`, { duration: Date.now() - startTime });
console.error(`[${jobId}] Job failed`, { error: error.message });

Track Metrics

  • Success rate
  • Average processing time
  • Error distribution
  • Usage patterns

Testing

Test the Full Flow

  1. 402 response format
  2. Payment verification
  3. Job creation
  4. Status polling
  5. Success/failure states

Test Edge Cases

  • Invalid inputs
  • Timeouts
  • Concurrent requests
  • Payment failures