# x402 Puppet API > AI face animation — animate any portrait with a driving video. > Pay per generation with USDC on Base. No API keys required. ## Base URL https://x402puppet.com ## x402 Payment Flow 1. POST to the endpoint without payment headers 2. Receive 402 response with `PAYMENT-REQUIRED` header (base64-encoded JSON) 3. Decode the requirements, sign an EIP-712 authorization with your wallet 4. Retry the POST with `PAYMENT-SIGNATURE` header containing the signed payload (base64-encoded) 5. Receive the result on success, plus a `PAYMENT-RESPONSE` header with the settlement receipt ## Endpoints | Route | Method | Cost | Description | |-------|--------|------|-------------| | /api/generate-x402 | POST | $0.05 USDC | Generate face animation from source image + driving video | | /api/uploads | POST | $0.01 USDC | Get a client token for direct file upload to Vercel Blob | | /api/uploads/confirm | POST | Free | Confirm an upload and associate the blob URL | ## Network - Network: Base mainnet (eip155:8453) - Asset: USDC --- ## /api/generate-x402 Accepts two input modes. The recommended path is JSON with file URLs. Alternatively, send files directly as multipart/form-data. ### Option A: application/json with file URLs (recommended) Pass any publicly accessible HTTPS URLs for the source image and driving video. You can host files anywhere — e.g. [agentupload.dev](https://agentupload.dev), your own S3 bucket, or via the `/api/uploads` endpoint below. ```json { "source_image_url": "https://example.com/photo.jpg", "driving_video_url": "https://example.com/driving.mp4", "flag_relative": "true", "flag_do_crop": "true", "flag_pasteback": "true" } ``` URLs must be HTTPS. The `flag_*` fields are optional (all default to `"true"`). ### Option B: multipart/form-data (direct file upload) | Field | Type | Required | Description | |-------|------|----------|-------------| | source_image | File (image/*) | Yes | Portrait photo to animate (JPEG, PNG, WebP, max 10MB) | | driving_video | File (video/*) | Yes | Video providing the motion (MP4, MOV, WebM, max 50MB) | | flag_relative | string ("true"/"false") | No | Use relative motion transfer (default: "true") | | flag_do_crop | string ("true"/"false") | No | Auto-crop face region (default: "true") | | flag_pasteback | string ("true"/"false") | No | Paste animation back onto original image (default: "true") | ### Output (application/json) ```json { "videoUrl": "https://....blob.vercel-storage.com/...", "thumbnailUrl": "https://....blob.vercel-storage.com/...", "videoContentType": "video/mp4", "thumbnailContentType": "image/jpeg" } ``` `videoUrl` and `thumbnailUrl` are public URLs you can fetch directly. ### Example Flow ``` # Step 1: POST without payment — get requirements POST /api/generate-x402 Content-Type: application/json Body: { "source_image_url": "https://example.com/photo.jpg", "driving_video_url": "https://example.com/driving.mp4" } Response: 402 Payment Required Header: PAYMENT-REQUIRED: # Step 2: Sign payment and retry POST /api/generate-x402 Content-Type: application/json PAYMENT-SIGNATURE: Body: { "source_image_url": "https://example.com/photo.jpg", "driving_video_url": "https://example.com/driving.mp4" } Response: 200 OK Header: PAYMENT-RESPONSE: Body: { "videoUrl": "...", "thumbnailUrl": "...", "videoContentType": "video/mp4", "thumbnailContentType": "image/jpeg" } ``` --- ## /api/uploads (optional) If you don't have your own file hosting, you can upload files to Vercel Blob via this endpoint. This is a three-step flow: ### Step 1: Get upload token (x402-protected, $0.01) ``` POST /api/uploads Content-Type: application/json Body: { "filename": "photo.jpg", "contentType": "image/jpeg" } Response: 402 → sign and retry with PAYMENT-SIGNATURE Response: 200 OK { "uploadId": "", "clientToken": "", "pathname": "uploads//photo.jpg", "expiresAt": "2025-01-01T00:05:00.000Z" } ``` Allowed content types: image/jpeg, image/jpg, image/png, image/gif, image/webp, video/mp4, video/webm, video/mov. Max size: 10MB for images, 50MB for videos. Token expires in 5 minutes. ### Step 2: Upload file directly to Vercel Blob ```bash curl -X PUT "https://vercel.com/api/blob/?pathname=uploads//photo.jpg" \ -H "authorization: Bearer " \ -H "x-content-type: image/jpeg" \ -H "x-api-version: 11" \ --data-binary @photo.jpg ``` Response includes `{ "url": "https://....blob.vercel-storage.com/..." }`. ### Step 3: Confirm upload (free, no payment) ``` POST /api/uploads/confirm Content-Type: application/json Body: { "uploadId": "", "blobUrl": "https://....blob.vercel-storage.com/..." } Response: 200 OK { "success": true, "upload": { "id": "...", "blobUrl": "...", "filename": "...", "contentType": "..." } } ``` The `blobUrl` from Step 2/3 can then be used as `source_image_url` or `driving_video_url` in `/api/generate-x402`. --- ## Preset Driving Videos Ready-to-use driving videos hosted at the base URL. Fetch these directly — no upload needed, just download and send as the `driving_video` field. | URL | Description | |-----|-------------| | /examples/driving/d6.mp4 | Eyebrow dance — rhythmic eyebrow raises and wiggles | | /examples/driving/d11.mp4 | Singing/lip-sync — exaggerated mouth movements and head bops | | /examples/driving/d12.mp4 | Head dance — side-to-side head swaying with silly expressions | | /examples/driving/d14.mp4 | Crazy eye dance — wide dramatic eye movements with a smile | ## Tips for Agents - Source image should contain a clear face (frontal or slight angle works best) - Driving video should be short (2-10 seconds) for best results - Generation takes 30-120 seconds depending on video length - Results are returned as public URLs — fetch or embed them directly - The generate endpoint has a 5-minute timeout - If you receive a non-402 error, do NOT retry with payment — investigate the error first - The simplest flow: host files on any HTTPS URL (e.g. agentupload.dev) and pass them as JSON body to `/api/generate-x402` - You can also use the preset driving videos above — just fetch the URL and include the file in your multipart/form-data request