Developer API Documentation
Introduction
The PicPuzzle API enables programmatic creation of puzzles. This REST API allows applications to create puzzles with images from a URL, generated via AI based on a text prompt, or provided as a base64-encoded string.
Base URL
https://api.picpuzzle.xyz/apiAuthentication
Currently, the API is open for use without authentication. Future versions may require API keys for rate limiting and security.
Endpoints
Create Puzzle
Creates a new puzzle with either an AI-generated image or an image from a URL.
/puzzles/createContent-Type: application/json
Generate AI Image
Generates an image via AI using a text prompt. Supports returning either a CDN URL or a base64-encoded image.
/puzzles/generate-imageContent-Type: application/json
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| prompt | string | Yes | Text prompt for AI image generation |
| response_format | string | No | Optional: "url" (default) or "base64" |
Examples
Return URL (default):
// POST https://api.picpuzzle.xyz/api/puzzles/generate-image
{
"prompt": "A cozy cabin in a snowy forest at twilight"
}Return Base64:
// POST https://api.picpuzzle.xyz/api/puzzles/generate-image
{
"prompt": "A cozy cabin in a snowy forest at twilight",
"response_format": "base64"
}Response Format
Success Response (200 OK) - URL:
{
"data": {
"url": "https://cdn.picpuzzle.xyz/puzzles/1234/generated.jpg"
}
}Success Response (200 OK) - Base64:
{
"data": {
"base64": "/9j/4AAQSkZJRgABAQAAAQABAAD..."
}
}Error Responses:
Missing Prompt (400)
{
"error": "Prompt is required"
}Generation Failure (500)
{
"error": "Failed to generate image",
"message": "<detailed error message>"
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| image_type | string | Yes | Source of the image: "ai", "url", or "base64" |
| prompt | string | Yes (if image_type="ai") | Text prompt for AI image generation |
| image_url | string | Yes (if image_type="url") | URL of the image to use for the puzzle |
| image_base64 | string | Yes (if image_type="base64") | Base64-encoded image string or Data URI (e.g., data:image/jpeg;base64,...) |
| difficulty | string | Yes | Puzzle difficulty: "easy", "medium", or "hard" |
| creatorName | string | Yes | Name of the puzzle creator |
| message | string | No | Optional message to display with the puzzle |
| secretMessage | string | No | Optional message revealed only when puzzle is solved |
| notify_email | string | No | Email to notify when the puzzle is attempted or completed |
| is_public | boolean | No | Set true to make the puzzle publicly visible (also accepts isPublic) |
| subid | string | No | Subscriber/user identifier for tracking and retrieving puzzles |
| subid2 | string | No | Secondary subscriber/user identifier for tracking and retrieving puzzles |
| webhook_url | string | No | Optional webhook URL to receive notifications for puzzle events (attempted, completed, leaderboard_submitted) |
Example Requests
AI-generated image:
// POST https://api.picpuzzle.xyz/api/puzzles/create
{
"image_type": "ai",
"prompt": "A serene mountain lake with snow-capped peaks at sunset",
"difficulty": "medium",
"creatorName": "API Demo",
"message": "Can you solve this puzzle?",
"secretMessage": "Congratulations on solving this AI-generated puzzle!",
"notify_email": "creator@example.com",
"webhook_url": "https://your-app.com/webhooks/puzzle-events",
"is_public": true,
"subid": "user123",
"subid2": "category_nature"
}URL image:
// POST https://api.picpuzzle.xyz/api/puzzles/create
{
"image_type": "url",
"image_url": "https://example.com/image.jpg",
"difficulty": "hard",
"creatorName": "API Demo",
"message": "This is a challenging puzzle!",
"secretMessage": "Well done on solving this difficult puzzle!",
"notify_email": "creator@example.com",
"webhook_url": "https://your-app.com/webhooks/puzzle-events",
"is_public": false,
"subid": "user456",
"subid2": "category_photos"
}Base64 image:
// POST https://api.picpuzzle.xyz/api/puzzles/create
{
"image_type": "base64",
"image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...",
"difficulty": "medium",
"creatorName": "API Demo",
"message": "Photo from mobile app selection",
"secretMessage": "Only visible after solving!",
"notify_email": "creator@example.com",
"webhook_url": "https://your-app.com/webhooks/puzzle-events",
"is_public": true,
"subid": "user789"
}Response Format
Success Response (201 Created):
{
"success": true,
"message": "Puzzle created successfully",
"puzzle": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"shareCode": "ABCD1234",
"shareUrl": "https://picpuzzle.xyz/puzzle/ABCD1234",
"playUrl": "https://picpuzzle.xyz/puzzle/ABCD1234",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"subid": "user123"
}
}Important Response Fields
- id: Unique puzzle identifier
- shareCode: Short code for sharing
- shareUrl: Complete URL that can be shared with users to solve the puzzle
- playUrl: Complete URL for playing the puzzle (same as shareUrl)
- accessToken: Token required for deleting the puzzle (store securely)
- subid: Subscriber/user identifier (if provided in request)
Error Responses
Missing Required Parameters (400)
{
"error": "Missing required fields",
"required": ["image_type", "creatorName", "difficulty"]
}Invalid Image Type (400)
{
"error": "Invalid image_type",
"message": "image_type must be 'ai', 'url', or 'base64'"
}Missing Prompt (400)
{
"error": "Missing prompt",
"message": "A prompt is required when image_type is 'ai'"
}Missing Base64 Image (400)
{
"error": "Missing image_base64",
"message": "An image_base64 string is required when image_type is 'base64'"
}Invalid Difficulty (400)
{
"error": "Invalid difficulty",
"validOptions": ["easy", "medium", "hard"]
}List Public Puzzles
Retrieve a paginated list of puzzles that are publicly visible.
/puzzles/publicQuery Parameters:
limit(optional, default 10): Maximum number of puzzles to returnoffset(optional, default 0): Number of puzzles to skip for pagination
Each puzzle object now includes a leaderboard array ordered by fastest completion time. The array is truncated to the top 10 attempts by default.
Example:
curl "https://api.picpuzzle.xyz/api/puzzles/public?limit=5&offset=0"
Success Response (200 OK):
{
"puzzles": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"shareCode": "ABCD1234",
"creatorName": "API Demo",
"imageUrl": "https://cdn.picpuzzle.xyz/puzzles/550e8400-e29b-41d4-a716-446655440000/original.jpg",
"difficulty": "medium",
"createdAt": "2024-05-01T12:34:56.000Z",
"playUrl": "https://picpuzzle.xyz/puzzle/ABCD1234",
"leaderboard": [
{ "player_name": "SpeedSolver", "time_in_seconds": 45, "completed_at": "2024-05-01T14:30:15.000Z" },
{ "player_name": "PuzzleMaster", "time_in_seconds": 67, "completed_at": "2024-05-01T13:45:22.000Z" }
]
}
]
}Retrieve Puzzle
Retrieve puzzles by subscriber ID, share code, or puzzle ID. Note: subid and subid2 may return multiple puzzles, while shareCode and puzzleId return a single puzzle.
/puzzles/retrieveQuery Parameters (at least one required):
subid(optional): Subscriber/user identifier (returns multiple puzzles)subid2(optional): Secondary subscriber/user identifier (returns multiple puzzles)shareCode(optional): Puzzle share code (returns single puzzle)puzzleId(optional): Puzzle unique identifier (returns single puzzle)
Examples:
// Retrieve by subscriber ID (returns multiple puzzles) curl "https://api.picpuzzle.xyz/api/puzzles/retrieve?subid=user123" // Retrieve by secondary subscriber ID (returns multiple puzzles) curl "https://api.picpuzzle.xyz/api/puzzles/retrieve?subid2=category_nature" // Retrieve by share code (returns single puzzle) curl "https://api.picpuzzle.xyz/api/puzzles/retrieve?shareCode=ABCD1234" // Retrieve by puzzle ID (returns single puzzle) curl "https://api.picpuzzle.xyz/api/puzzles/retrieve?puzzleId=550e8400-e29b-41d4-a716-446655440000"
Success Response - Single Puzzle (200 OK):
When retrieving by shareCode or puzzleId: The leaderboard array is truncated to the top 10 attempts by default.
{
"success": true,
"puzzle": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"creator_name": "API Demo",
"message": "Test puzzle message",
"image_url": "https://cdn.picpuzzle.xyz/puzzles/550e8400-e29b-41d4-a716-446655440000/original.jpg",
"difficulty": "medium",
"created_at": "2024-05-01T12:34:56.000Z",
"tile_count": 16,
"share_code": "ABCD1234",
"completed": false,
"secret_message": "Congratulations!",
"is_public": true,
"subid": "user123",
"subid2": "category_nature",
"webhookUrl": "https://your-app.com/webhooks/puzzle-events",
"playUrl": "https://picpuzzle.xyz/puzzle/ABCD1234",
"leaderboard": [
{ "player_name": "SpeedSolver", "time_in_seconds": 45, "completed_at": "2024-05-01T14:30:15.000Z" },
{ "player_name": "QuickFingers", "time_in_seconds": 89, "completed_at": "2024-05-01T12:20:08.000Z" }
]
}
}Success Response - Multiple Puzzles (200 OK):
When retrieving by subid or subid2:
{
"success": true,
"puzzles": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"creator_name": "API Demo",
"message": "Test puzzle message",
"image_url": "https://cdn.picpuzzle.xyz/puzzles/550e8400-e29b-41d4-a716-446655440000/original.jpg",
"difficulty": "medium",
"created_at": "2024-05-01T12:34:56.000Z",
"tile_count": 16,
"share_code": "ABCD1234",
"completed": false,
"secret_message": "Congratulations!",
"is_public": true,
"subid": "user123",
"subid2": "category_nature",
"webhookUrl": "https://your-app.com/webhooks/puzzle-events",
"playUrl": "https://picpuzzle.xyz/puzzle/ABCD1234"
},
{
"id": "660f9511-f3ac-52e5-b827-557766551111",
"creator_name": "API Demo",
"message": "Another puzzle",
"image_url": "https://cdn.picpuzzle.xyz/puzzles/660f9511-f3ac-52e5-b827-557766551111/original.jpg",
"difficulty": "easy",
"created_at": "2024-05-02T10:15:30.000Z",
"tile_count": 9,
"share_code": "EFGH5678",
"completed": false,
"secret_message": "Well done!",
"is_public": false,
"subid": "user123",
"subid2": "category_nature",
"webhookUrl": "https://your-app.com/webhooks/puzzle-events",
"playUrl": "https://picpuzzle.xyz/puzzle/EFGH5678",
"leaderboard": []
}
]
}Error Responses:
Missing Identifier (400)
{
"success": false,
"error": "At least one identifier required"
}Puzzle Not Found (404)
{
"success": false,
"error": "Puzzle not found"
}Update Puzzle
Update specific properties of a puzzle using subid, subid2, shareCode, or puzzleId. Requires the accessToken for verification. Note: subid and subid2 may update multiple puzzles.
/puzzles/updateContent-Type: application/json
Request Body Parameters (at least one identifier required):
subid(optional): Subscriber/user identifier (may update multiple puzzles)subid2(optional): Secondary subscriber/user identifier (may update multiple puzzles)shareCode(optional): Puzzle share code (updates single puzzle)puzzleId(optional): Puzzle unique identifier (updates single puzzle)accessToken(required): Access token for verification
Updatable properties:
- If there have been NO attempts:
difficulty,creatorName,message,secret_message,notify_email,is_public,subid,subid2 - If attempts exist:
notify_email,is_public,subid,subid2
Examples:
// Update public visibility and notification email by share code
curl -X PATCH "https://api.picpuzzle.xyz/api/puzzles/update" \
-H "Content-Type: application/json" \
-d '{
"shareCode": "ABCD1234",
"accessToken": "your-access-token-here",
"is_public": true,
"notify_email": "creator@example.com"
}'
// Update difficulty and creatorName (only if no attempts)
curl -X PATCH "https://api.picpuzzle.xyz/api/puzzles/update" \
-H "Content-Type: application/json" \
-d '{
"puzzleId": "550e8400-e29b-41d4-a716-446655440000",
"accessToken": "your-access-token-here",
"difficulty": "hard",
"creatorName": "New Name"
}'
// Bulk update by subid (may affect multiple puzzles)
curl -X PATCH "https://api.picpuzzle.xyz/api/puzzles/update" \
-H "Content-Type: application/json" \
-d '{
"subid": "user123",
"accessToken": "your-access-token-here",
"notify_email": "new-email@example.com",
"is_public": false
}'Success Response (200 OK):
// Single puzzle update
{
"success": true,
"message": "Puzzle updated successfully",
"updatedCount": 1
}
// Multiple puzzle update (by subid or subid2)
{
"success": true,
"message": "3 puzzles updated successfully",
"updatedCount": 3
}Error Responses:
Missing Identifier (400)
{
"error": "Missing identifier",
"message": "At least one identifier (subid, subid2, shareCode, or puzzleId) must be provided"
}Missing Access Token (400)
{
"error": "Missing access token",
"message": "Access token is required for puzzle update"
}Invalid Access Token (403)
{
"error": "Forbidden",
"message": "Invalid access token"
}Puzzle Not Found (404)
{
"error": "Puzzle not found",
"message": "No puzzle matched the provided identifiers"
}Invalid Difficulty (400)
{
"error": "Invalid difficulty",
"message": "Invalid difficulty. Allowed: easy, medium, hard"
}No Updatable Properties (400)
{
"error": "No updatable properties provided",
"message": "Provide one or more allowed properties to update"
}Delete Puzzle
Delete puzzle(s) using subid, subid2, share code, or puzzle ID. Requires the access token for verification. Note: subid and subid2 may delete multiple puzzles.
/puzzles/deleteContent-Type: application/json
Request Body Parameters (at least one identifier required):
subid(optional): Subscriber/user identifier (may delete multiple puzzles)subid2(optional): Secondary subscriber/user identifier (may delete multiple puzzles)shareCode(optional): Puzzle share code (deletes single puzzle)puzzleId(optional): Puzzle unique identifier (deletes single puzzle)accessToken(required): Access token for verification
Examples:
// Delete by subscriber ID (may delete multiple puzzles)
curl -X DELETE "https://api.picpuzzle.xyz/api/puzzles/delete" \
-H "Content-Type: application/json" \
-d '{
"subid": "user123",
"accessToken": "your-access-token-here"
}'
// Delete by secondary subscriber ID (may delete multiple puzzles)
curl -X DELETE "https://api.picpuzzle.xyz/api/puzzles/delete" \
-H "Content-Type: application/json" \
-d '{
"subid2": "category_nature",
"accessToken": "your-access-token-here"
}'
// Delete by share code
curl -X DELETE "https://api.picpuzzle.xyz/api/puzzles/delete" \
-H "Content-Type: application/json" \
-d '{
"shareCode": "ABCD1234",
"accessToken": "your-access-token-here"
}'
// Delete by puzzle ID
curl -X DELETE "https://api.picpuzzle.xyz/api/puzzles/delete" \
-H "Content-Type: application/json" \
-d '{
"puzzleId": "550e8400-e29b-41d4-a716-446655440000",
"accessToken": "your-access-token-here"
}'Success Response (200 OK):
// Single puzzle deletion
{
"success": true,
"message": "Puzzle deleted successfully",
"deletedCount": 1
}
// Multiple puzzle deletion (by subid or subid2)
{
"success": true,
"message": "3 puzzles deleted successfully",
"deletedCount": 3
}Error Responses:
Missing Identifier (400)
{
"success": false,
"error": "At least one identifier (subid, subid2, shareCode, or puzzleId) is required"
}Missing Access Token (400)
{
"success": false,
"error": "accessToken is required"
}Invalid Access Token (403)
{
"success": false,
"error": "Invalid access token"
}Puzzle Not Found (404)
{
"success": false,
"error": "Puzzle not found"
}Get Puzzle Leaderboard
Retrieve the leaderboard for a specific puzzle using either the puzzle ID or share code.
Endpoint:
GET /api/puzzles/{puzzleId}/leaderboardExample with Puzzle ID:
// GET https://api.picpuzzle.xyz/api/puzzles/123/leaderboard
Example with Share Code:
// GET https://api.picpuzzle.xyz/api/puzzles/ABC123/leaderboard
Response:
{
"leaderboard": [
{
"id": 1,
"player_name": "Alice",
"completion_time": 45.2,
"attempts": 1,
"completed_at": "2024-01-15T10:30:00Z"
},
{
"id": 2,
"player_name": "Bob",
"completion_time": 52.8,
"attempts": 2,
"completed_at": "2024-01-15T11:15:00Z"
}
]
}Code Example
JavaScript (Node.js):
const axios = require('axios');
async function createPuzzle() {
try {
const response = await axios.post('https://api.picpuzzle.xyz/api/puzzles/create', {
image_type: 'url',
image_url: 'https://picsum.photos/800/600', // Random image for testing
difficulty: 'medium',
creatorName: 'API Demo',
message: 'This puzzle was created via the API!',
secretMessage: 'Congratulations on solving the API-created puzzle!',
is_public: true
});
console.log('Success! Puzzle created:');
console.log(`Share URL: ${response.data.puzzle.shareUrl}`);
if (response.data.puzzle.shareCode) {
console.log(`Share Code: ${response.data.puzzle.shareCode}`);
}
return response.data;
} catch (error) {
console.error('Error creating puzzle:');
if (error.response) {
console.error(`Status: ${error.response.status}`);
console.error(error.response.data);
if (error.response.data?.error || error.response.data?.message) {
console.error(`API error: ${error.response.data.error || error.response.data.message}`);
}
} else if (error.request) {
console.error('No response received from server.');
} else {
console.error(error.message);
}
}
}
createPuzzle();Note: Remember to handle errors appropriately in your production code.
AI Image Generation
The PicPuzzle API leverages X.AI's 'grok-2-image' model for generating high-quality images from text prompts. When using the AI option, provide a descriptive prompt for best results.
Tips for Effective Prompts:
- Be detailed and specific about what you want in the image
- Describe style, lighting, and mood for more control
- Include subject, setting, and any important visual elements
- Keep prompts clear and focused for best results
Webhooks
PicPuzzle supports webhooks to notify your application when specific events occur with your puzzles. When creating a puzzle, you can provide a webhook_url to receive real-time notifications.
Webhook Events
The following events trigger webhook notifications:
- attempted - Fired when a player makes an attempt on the puzzle
- completed - Fired when a player successfully completes the puzzle
- leaderboard_submitted - Fired when a completed attempt is added to the leaderboard
Webhook Payload Format
All webhook payloads are sent as HTTP POST requests with the following structure:
{
"event": "event_type",
"puzzle": {
"id": "puzzle_uuid",
"shareCode": "ABCD1234",
"creatorName": "Creator Name",
"subid": "user123",
"subid2": "category_nature"
},
"data": {
// Event-specific data (see below)
},
"timestamp": "2024-05-01T14:30:15.000Z"
}Event-Specific Data
attempted:
{
"data": {
"playerName": "Player123",
"timeInSeconds": 45,
"isCompleted": false
}
}completed:
{
"data": {
"playerName": "Player123",
"timeInSeconds": 45,
"completedAt": "2024-05-01T14:30:15.000Z"
}
}leaderboard_submitted:
{
"data": {
"playerName": "Player123",
"timeInSeconds": 45,
"position": 1,
"completedAt": "2024-05-01T14:30:15.000Z"
}
}Security Considerations
- Webhook URLs must be HTTPS endpoints
- Implement proper authentication/validation on your webhook endpoint
- Consider implementing idempotency to handle duplicate webhook deliveries
Testing Webhooks
You can use services like webhook.site orngrok to test webhook functionality during development.
Rate Limiting & Future Plans
Currently, there are no rate limits enforced on the API. However, please use the API responsibly. Future versions may include rate limiting, authentication, and additional endpoints for puzzle management.