{"info":{"_postman_id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","name":"Printora Partner API","description":"<html><head></head><body><h1 id=\"printora-partner-integration-api\">Printora Partner Integration API</h1>\n<p>The Printora Partner API allows partners to create custom print sessions where end-users can design and order personalized products using their own images.</p>\n<hr>\n<h2 id=\"🚀-quick-start\">🚀 Quick Start</h2>\n<h3 id=\"integration-flow\">Integration Flow</h3>\n<ol>\n<li><p><strong>Create Session</strong> - Partner creates a session with an image URL via API</p>\n</li>\n<li><p><strong>User Redirect</strong> - User visits the redirect URL and is automatically logged in</p>\n</li>\n<li><p><strong>User Customizes</strong> - User selects products and customizes their design (via Printora frontend)</p>\n</li>\n<li><p><strong>Checkout</strong> - User completes checkout, order is created</p>\n</li>\n<li><p><strong>Webhook Notification</strong> - Partner receives webhook notification about the order</p>\n</li>\n<li><p><strong>Retrieve Orders</strong> - Partner can retrieve order details and tracking via API</p>\n</li>\n</ol>\n<hr>\n<h2 id=\"🔐-authentication\">🔐 Authentication</h2>\n<p>All API requests require authentication using your Partner API Key in the Authorization header:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Bearer sk_test_printora_partner_demo_12345678\n\n</code></pre>\n<p><strong>API Key Format:</strong></p>\n<ul>\n<li><p>Test mode: <code>sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxx</code></p>\n</li>\n<li><p>Live mode: <code>sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxx</code></p>\n</li>\n</ul>\n<hr>\n<h2 id=\"🌍-base-urls\">🌍 Base URLs</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Environment</th>\n<th>Base URL</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Production</strong></td>\n<td><a href=\"https://api.printora.ai\">https://api.printora.ai</a></td>\n</tr>\n<tr>\n<td><strong>Staging</strong></td>\n<td><a href=\"https://api-staging.printora.ai\">https://api-staging.printora.ai</a></td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2 id=\"📚-available-endpoints\">📚 Available Endpoints</h2>\n<h3 id=\"session-management\">Session Management</h3>\n<ul>\n<li><strong>POST</strong> <code>/api/v1/partner-session</code> - Create a new partner session</li>\n</ul>\n<h3 id=\"order-management\">Order Management</h3>\n<ul>\n<li><strong>GET</strong> <code>/api/v1/partners/:partnerId/orders</code> - List all orders for the partner</li>\n</ul>\n<h3 id=\"webhook-management\">Webhook Management</h3>\n<ul>\n<li><p><strong>GET</strong> <code>/api/v1/webhooks/logs</code> - View webhook delivery logs</p>\n</li>\n<li><p><strong>POST</strong> <code>/api/v1/webhooks/resend</code> - Manually resend a webhook</p>\n</li>\n<li><p><strong>POST</strong> <code>/api/v1/webhooks/retry</code> - Retry a failed webhook delivery</p>\n</li>\n</ul>\n<hr>\n<h2 id=\"⚠️-important-notes\">⚠️ Important Notes</h2>\n<h3 id=\"api-scope\">API Scope</h3>\n<p>This API is designed <strong>exclusively for partner backend integration</strong>.</p>\n<p><strong>Partners CAN:</strong></p>\n<ul>\n<li><p>✅ Create print sessions for end-users</p>\n</li>\n<li><p>✅ Retrieve orders created through their sessions</p>\n</li>\n<li><p>✅ Manage webhook deliveries and view logs</p>\n</li>\n</ul>\n<p><strong>Partners CANNOT:</strong></p>\n<ul>\n<li><p>❌ Access cart endpoints (internal frontend use only)</p>\n</li>\n<li><p>❌ Access checkout endpoints (internal frontend use only)</p>\n</li>\n<li><p>❌ Access user authentication or product management endpoints</p>\n</li>\n</ul>\n<h3 id=\"session-lifecycle\">Session Lifecycle</h3>\n<ul>\n<li><p><strong>Redirect URL expiry:</strong> 15 minutes from creation</p>\n</li>\n<li><p><strong>Session expiry:</strong> 24 hours after user first accesses the redirect URL</p>\n</li>\n<li><p><strong>Session statuses:</strong> <code>pending</code> → <code>active</code> → <code>completed</code> / <code>expired</code> / <code>cancelled</code></p>\n</li>\n</ul>\n<hr>\n<h2 id=\"🔔-webhooks\">🔔 Webhooks</h2>\n<p>Partners receive webhook notifications for the following events:</p>\n<ul>\n<li><p><code>order.created</code> - When a user completes checkout</p>\n</li>\n<li><p><code>order.paid</code> - When payment is confirmed</p>\n</li>\n<li><p><code>order.shipped</code> - When the order is shipped</p>\n</li>\n<li><p><code>order.delivered</code> - When the order is delivered</p>\n</li>\n<li><p><code>order.cancelled</code> - When an order is cancelled</p>\n</li>\n</ul>\n<p><strong>Webhook Payload Example:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{\n  \"sessionId\": \"cc8930e4-621a-xxxxx-xxxxx\",\n  \"event\": \"order.created\",\n  \"data\": {\n    \"order_id\": \"ord_abc123\",\n    \"session_id\": \"sess_x1y2z3\",\n    \"status\": \"pending\",\n    \"total_amount\": 29.99,\n    \"currency\": \"USD\"\n  },\n  \"timestamp\": \"2026-01-30T10:40:00Z\"\n}\n\n</code></pre><hr>\n<h2 id=\"📊-rate-limits\">📊 Rate Limits</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Metric</th>\n<th>Limit</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Requests per minute</td>\n<td>60</td>\n</tr>\n<tr>\n<td>Requests per day</td>\n<td>10,000</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Rate limit headers are included in every response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>X-RateLimit-Limit: 60\nX-RateLimit-Remaining: 45\nX-RateLimit-Reset: 1738234567\n\n</code></pre><hr>\n<h2 id=\"🛠️-support\">🛠️ Support</h2>\n<p>Need help with the integration?</p>\n<ul>\n<li><p><strong>Email:</strong> <a href=\"https://mailto:support@printora.ai\">support@printora.ai</a></p>\n</li>\n<li><p><strong>Documentation:</strong> <a href=\"https://docs.printora.ai/partner-api\">View complete documentation →</a></p>\n</li>\n</ul>\n<hr>\n<h2 id=\"📖-getting-started\">📖 Getting Started</h2>\n<ol>\n<li><p><strong>Set up your environment</strong> - Select the appropriate environment (Staging/Production) from the dropdown</p>\n</li>\n<li><p><strong>Configure your API key</strong> - Update the <code>PARTNER_API_KEY</code> variable in the collection</p>\n</li>\n<li><p><strong>Test the flow</strong> - Start with \"Create Session\" to test the integration</p>\n</li>\n<li><p><strong>Review responses</strong> - Check the response examples to understand the data structure</p>\n</li>\n<li><p><strong>Implement webhooks</strong> - Set up your webhook endpoint to receive order notifications</p>\n</li>\n</ol>\n<hr>\n<p><strong>Version:</strong> 1.0<br><strong>Last Updated:</strong> February 2026<br><strong>Status:</strong> ✅ Production Ready</p>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"Printora Partner Integration API","slug":"printora-partner-integration-api"}],"owner":"31908428","collectionId":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","publishedId":"2sBXcHhJd9","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-02-27T06:02:29.000Z"},"item":[{"name":"Session Management","item":[{"name":"Create Session","id":"a423878f-6c5c-469d-b38b-f600f5ef5236","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":false},"method":"POST","header":[{"key":"idempotency-key","value":"","type":"text"}],"body":{"mode":"raw","raw":"{\r\n  \"imageUrl\": \"https://picsum.photos/3000/3000\",\r\n//   \"userData\": {\r\n//     \"email\": \"a1slcfrfmd@xkxkud.com\",\r\n//     \"name\": \"John Simon\",\r\n//     \"firstName\": \"John\",\r\n//     \"lastName\": \"Simon\"\r\n//   },\r\n  \"failedUrl\" : \"https://shopee.co.id\",\r\n  \"successUrl\" : \"https://favos.app\"\r\n}","options":{"raw":{"language":"json"}}},"url":"/api/v1/partner-session","description":"<h1 id=\"create-partner-session\">Create Partner Session</h1>\n<p>Creates a new partner session and returns a redirect URL for the end-user to customize products.</p>\n<hr />\n<h2 id=\"📥-request\">📥 Request</h2>\n<p><strong>Endpoint:</strong> <code>POST /api/v1/partner-session</code></p>\n<p><strong>Description:</strong> Create a design session for a customer. Returns a redirect URL to Printora checkout page.</p>\n<p><strong>Authentication:</strong> Required</p>\n<p><strong>Headers:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Bearer YOUR_API_KEY\nIdempotency-Key: 550e8400-e29b-41d4-a716-446655440000\nContent-Type: application/json\n\n</code></pre>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Header</th>\n<th>Required</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>Authorization</code></td>\n<td><strong>Yes</strong></td>\n<td>Bearer token with your API key</td>\n</tr>\n<tr>\n<td><code>Idempotency-Key</code></td>\n<td><strong>Yes</strong></td>\n<td>Unique key to prevent duplicate session creation (UUID recommended)</td>\n</tr>\n<tr>\n<td><code>Content-Type</code></td>\n<td><strong>Yes</strong></td>\n<td>Must be <code>application/json</code></td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h2 id=\"📥-request-body\">📥 Request Body</h2>\n<p><strong>Request Body:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"imageUrl\": \"https://partner.com/customer-design.png\",\n  \"userData\": {\n    \"email\": \"customer@example.com\",\n    \"firstName\": \"John\",\n    \"lastName\": \"Doe\",\n    \"name\": \"John Doe\"\n  },\n  \"successUrl\": \"https://partner.com/order-success\",\n  \"failedUrl\": \"https://partner.com/order-failed\"\n}\n\n</code></pre>\n<hr />\n<h2 id=\"📥-request-body-parameters\">📥 Request Body Parameters</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Required</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>imageUrl</code></td>\n<td>String</td>\n<td><strong>Yes</strong></td>\n<td>URL of customer's design image (must be publicly accessible)</td>\n</tr>\n<tr>\n<td><code>userData</code></td>\n<td>Object</td>\n<td><strong>No</strong></td>\n<td>Customer information (optional, improves checkout UX)</td>\n</tr>\n<tr>\n<td><code>userData.email</code></td>\n<td>String</td>\n<td>No</td>\n<td>Customer email - pre-fills checkout form</td>\n</tr>\n<tr>\n<td><code>userData.firstName</code></td>\n<td>String</td>\n<td>No</td>\n<td>Customer first name - pre-fills checkout form</td>\n</tr>\n<tr>\n<td><code>userData.lastName</code></td>\n<td>String</td>\n<td>No</td>\n<td>Customer last name - pre-fills checkout form</td>\n</tr>\n<tr>\n<td><code>userData.name</code></td>\n<td>String</td>\n<td>No</td>\n<td>Customer display name</td>\n</tr>\n<tr>\n<td><code>successUrl</code></td>\n<td>String</td>\n<td><strong>Yes</strong></td>\n<td>Redirect URL after successful payment</td>\n</tr>\n<tr>\n<td><code>failedUrl</code></td>\n<td>String</td>\n<td><strong>Yes</strong></td>\n<td>Redirect URL after failed payment</td>\n</tr>\n<tr>\n<td><code>idempotencyKey</code></td>\n<td>String</td>\n<td>No</td>\n<td>Unique key to prevent duplicate session creation</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Why include</strong> <strong><code>userData</code>****?</strong> <em>(Optional, but recommended)</em></p>\n<p>Providing customer information improves the checkout experience:</p>\n<ul>\n<li><p>✅ <strong>Faster checkout</strong> - Email and name are pre-filled at checkout</p>\n</li>\n<li><p>✅ <strong>Reduced friction</strong> - Customer doesn't re-enter information they already provided on your site</p>\n</li>\n<li><p>✅ <strong>Better UX</strong> - Seamless flow from your platform to Printora</p>\n</li>\n</ul>\n<p><strong>Privacy &amp; Security:</strong></p>\n<ul>\n<li><p>Customer data is only used for order processing and fulfillment</p>\n</li>\n<li><p>Data is not shared with third parties</p>\n</li>\n<li><p>Customer can update information during checkout if needed</p>\n</li>\n<li><p>User accounts are created automatically AFTER successful payment (not during session creation)</p>\n</li>\n<li><p>If <code>userData</code> is not provided, customer will enter information manually at checkout</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"📤-response-fields\">📤 Response Fields</h2>\n<h3 id=\"success-response-201-created\">Success Response (201 Created)</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>success</code></td>\n<td>Boolean</td>\n<td><code>true</code> if session created successfully, <code>false</code> if error</td>\n</tr>\n<tr>\n<td><code>data.sessionId</code></td>\n<td>String (UUID)</td>\n<td>Unique identifier for this partner session (use for tracking)</td>\n</tr>\n<tr>\n<td><code>data.redirectUrl</code></td>\n<td>String (URL)</td>\n<td>Full URL to redirect customer to Printora checkout page. Direct the customer to this URL to complete the order.</td>\n</tr>\n<tr>\n<td><code>data.imageUrl</code></td>\n<td>String (URL)</td>\n<td>Echo of the customer's design image URL you provided</td>\n</tr>\n<tr>\n<td><code>data.createdAt</code></td>\n<td>String (ISO8601)</td>\n<td>Timestamp when session was created</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Response Example:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"sessionId\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"redirectUrl\": \"https://printora.ai/en/print/daeb7111155d08bc92abe7aabf27782e5ceae0626a5ce2cbad9c99d75a1adf37\",\n    \"imageUrl\": \"https://partner.com/customer-design.png\",\n    \"createdAt\": \"2026-01-31T10:00:00.000Z\"\n  }\n}\n\n</code></pre>\n<h3 id=\"idempotent-response-409-conflict\">Idempotent Response (409 Conflict)</h3>\n<p>If you send the same <code>idempotencyKey</code> twice, you'll get the existing session:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"sessionId\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"redirectUrl\": \"https://printora.ai/en/print/daeb7111155d08bc92abe7aabf27782e5ceae0626a5ce2cbad9c99d75a1adf37\",\n    \"imageUrl\": \"https://partner.com/customer-design.png\",\n    \"createdAt\": \"2026-01-31T10:00:00.000Z\"\n  }\n}\n\n</code></pre>\n<hr />\n<h2 id=\"🚫-error-responses\">🚫 Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>400</td>\n<td><code>INVALID_IMAGE_URL</code></td>\n<td>Image URL is invalid or not accessible</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>successUrl is required</code></td>\n<td>successUrl is required and must be a valid URL</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>failedUrl is required</code></td>\n<td>failedUrl is required and must be a valid URL</td>\n</tr>\n<tr>\n<td>401</td>\n<td><code>INVALID_API_KEY</code></td>\n<td>Partner API key is invalid or revoked</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>DUPLICATE_SESSION</code></td>\n<td>Session with this idempotency_key already exists (returns existing session)</td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>RATE_LIMIT_EXCEEDED</code></td>\n<td>Too many requests, rate limit exceeded</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_IMAGE_URL\",\n    \"message\": \"Image URL must be a valid HTTPS URL\"\n  }\n}\n\n</code></pre>\n<hr />\n<h2 id=\"💡-example-use-case\">💡 Example Use Case</h2>\n<p><strong>Scenario:</strong> Photo printing service wants to let users print their Instagram photos</p>\n<ol>\n<li><p>Partner fetches image from user's Instagram</p>\n</li>\n<li><p>Partner calls this endpoint with image URL and user's email</p>\n</li>\n<li><p>Partner redirects user to <code>redirect_url</code></p>\n</li>\n<li><p>User selects product, customizes design, and completes checkout</p>\n</li>\n<li><p>Partner receives webhook notification when order is placed</p>\n</li>\n</ol>\n<hr />\n<h2 id=\"⏱️-session-expiry--token-validity\">⏱️ Session Expiry &amp; Token Validity</h2>\n<ul>\n<li><p><strong>Redirect URL validity:</strong> 15 minutes from creation</p>\n</li>\n<li><p><strong>Active session duration:</strong> 24 hours after user first accesses the URL</p>\n</li>\n<li><p><strong>Token validity:</strong> Token becomes invalid after order is created</p>\n</li>\n</ul>\n<h3 id=\"token-lifecycle-states\">Token Lifecycle States</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>State</th>\n<th><code>isValid</code></th>\n<th><code>isCompleted</code></th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>New Session</strong></td>\n<td><code>true</code></td>\n<td><code>false</code></td>\n<td>Token is ready to use</td>\n</tr>\n<tr>\n<td><strong>After Order Created</strong></td>\n<td><code>false</code></td>\n<td><code>true</code></td>\n<td>Token was used, cannot be reused</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Important:</strong> Each session token can only be used for ONE order. After order is created, the token becomes invalid.</p>\n<hr />\n<h2 id=\"🔗-how-it-works\">🔗 How It Works</h2>\n<h3 id=\"flow-overview\">Flow Overview</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>┌─────────────┐                    ┌─────────────┐\n│   Partner   │                    │   Printora   │\n│   Server    │                    │   Backend    │\n└──────┬──────┘                    └──────┬──────┘\n       │                                  │\n       │  1. POST /api/v1/partner-session    │\n       │     { imageUrl, userData, ... }    │\n       ├─────────────────────────────────&gt;│\n       │                                  │\n       │  2. Generate session + token       │\n       │                                  │\n       │&lt;─────────────────────────────────┤\n       │  {                               │\n       │    sessionId: \"uuid\",             │\n       │    redirectUrl: \"https://...\",   │\n       │  }                               │\n       │                                  │\n       │  3. Partner redirects user       │\n       ├─────────────────────────────────&gt;│\n       │                                  │\n       │  4. User validates token          │\n       │     GET /api/v1/partner-session/   │\n       │          by-token/:token           │\n       │                                  │\n       │  5. User customizes &amp; checks out  │\n       │                                  │\n       │  6. Token becomes INVALID         │\n       │     (marked as completed)        │\n       │                                  │\n       │  7. Partner receives webhook      │\n       │     order.paid with order details  │\n       │                                  │\n\n</code></pre><h3 id=\"step-by-step-process\">Step-by-Step Process:</h3>\n<ol>\n<li><p><strong>Partner creates session</strong></p>\n<ul>\n<li><p>POST to <code>/api/v1/partner-session</code> with image URL</p>\n</li>\n<li><p>Gets <code>redirectUrl</code> with temporary token</p>\n</li>\n<li><p>Gets <code>sessionId</code> for tracking</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Partner redirects user</strong></p>\n<ul>\n<li><p>User visits <code>https://printora.ai/en/print/{token}</code></p>\n</li>\n<li><p>Frontend validates token by calling <code>GET /api/v1/partner-session/by-token/:token</code></p>\n</li>\n</ul>\n</li>\n<li><p><strong>User customizes product</strong></p>\n<ul>\n<li><p>Frontend displays partner's image</p>\n</li>\n<li><p>User customizes the product</p>\n</li>\n</ul>\n</li>\n<li><p><strong>User completes checkout</strong></p>\n<ul>\n<li><p>User fills checkout form (pre-filled if <code>userData</code> was provided)</p>\n</li>\n<li><p>User completes payment</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Token becomes invalid</strong></p>\n<ul>\n<li><p>After order is created, <code>isValid</code> becomes <code>false</code></p>\n</li>\n<li><p>Token cannot be reused for another order</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Partner receives notification</strong></p>\n<ul>\n<li>Partner gets <code>order.paid</code> webhook with order details</li>\n</ul>\n</li>\n</ol>\n<hr />\n<h2 id=\"🔗-related-endpoints\">🔗 Related Endpoints</h2>\n<ul>\n<li><p><code>GET /api/v1/partner-session/by-token/:token</code> - Validate session token and check if still usable</p>\n</li>\n<li><p><code>GET /api/v1/partner-session/:sessionId</code> - Get session details by session ID</p>\n</li>\n<li><p><code>GET /api/v1/partners/orders</code> - Get all orders created from partner sessions</p>\n</li>\n<li><p><code>GET /api/v1/partners/webhook-logs</code> - View webhook delivery logs</p>\n</li>\n<li><p><code>POST /api/v1/partners/webhook-logs/resend</code> - Manually resend webhook by order</p>\n</li>\n<li><p><code>POST /api/v1/partners/webhook-logs/:webhookLogId/retry</code> - Retry failed webhook delivery</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"📝-full-example\">📝 Full Example</h2>\n<h3 id=\"javascriptnodejs-example\">JavaScript/Node.js Example</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">// Step 1: Create partner session\nconst response = await fetch('https://printora-be-staging.vercel.app/api/v1/partner-session', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Bearer YOUR_API_KEY',\n    'Content-Type': 'application/json',\n    'Idempotency-Key': '550e8400-e29b-41d4-a716-446655440000'\n  },\n  body: JSON.stringify({\n    imageUrl: 'https://partner.com/design.png',\n    userData: {\n      email: 'customer@example.com',\n      firstName: 'John',\n      lastName: 'Doe'\n    },\n    successUrl: 'https://partner.com/success',\n    failedUrl: 'https://partner.com/failed'\n  })\n});\nconst result = await response.json();\n// Step 2: Redirect user to Printora\nif (result.success) {\n  // Redirect user to complete their order\n  window.location.href = result.data.redirectUrl;\n  // Or save session ID for tracking\n  localStorage.setItem('partnerSessionId', result.data.sessionId);\n}\n\n</code></pre>\n<h3 id=\"curl-example\">cURL Example</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">curl -X POST https://printora-be-staging.vercel.app/api/v1/partner-session \\\n  -H \"Authorization: Bearer YOUR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -d '{\n    \"imageUrl\": \"https://partner.com/design.png\",\n    \"userData\": {\n      \"email\": \"customer@example.com\",\n      \"firstName\": \"John\",\n      \"lastName\": \"Doe\"\n    },\n    \"successUrl\": \"https://partner.com/success\",\n    \"failedUrl\": \"https://partner.com/failed\"\n  }'\n\n</code></pre>\n<hr />\n<h2 id=\"📊-response-data-usage\">📊 Response Data Usage</h2>\n<h3 id=\"for-partner-backend\">For Partner Backend:</h3>\n<ul>\n<li><p><strong><code>sessionId</code></strong> - Use for tracking and analytics</p>\n</li>\n<li><p><strong><code>redirectUrl</code></strong> - Direct user to this URL</p>\n</li>\n<li><p><strong>Extract temporary token</strong>: <code>redirectUrl.split('/').pop()</code></p>\n</li>\n</ul>\n<h3 id=\"for-frontend-printora\">For Frontend (Printora):</h3>\n<ul>\n<li><p>Validate token before allowing checkout</p>\n</li>\n<li><p>Display partner's image</p>\n</li>\n<li><p>Pre-fill user data if provided</p>\n</li>\n<li><p>Show error if token is invalid</p>\n</li>\n</ul>\n<h3 id=\"for-partner-dashboard\">For Partner Dashboard:</h3>\n<ul>\n<li><p>Track session conversions</p>\n</li>\n<li><p>Monitor which sessions resulted in orders</p>\n</li>\n<li><p>Calculate conversion rates</p>\n</li>\n</ul>\n","urlObject":{"path":["api","v1","partner-session"],"host":[""],"query":[],"variable":[]}},"response":[],"_postman_id":"a423878f-6c5c-469d-b38b-f600f5ef5236"}],"id":"f5b7ef89-3f8a-4c6f-88fc-001cbf2f467f","description":"<h1 id=\"session-management\">Session Management</h1>\n<p>Partner creates sessions for end-users to customize products with their images.</p>\n<h2 id=\"what-is-a-partner-session\">What is a Partner Session?</h2>\n<p>A partner session is a temporary workspace where end-users can:</p>\n<ul>\n<li><p>Upload or use a pre-provided image</p>\n</li>\n<li><p>Select products (t-shirts, mugs, etc.)</p>\n</li>\n<li><p>Customize their design</p>\n</li>\n<li><p>Complete checkout</p>\n</li>\n</ul>\n<h2 id=\"session-lifecycle\">Session Lifecycle</h2>\n<p>pending → active → completed<br />↓ ↓<br />expired cancelled</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pending</code></td>\n<td>Session created, user hasn't visited redirect URL yet</td>\n</tr>\n<tr>\n<td><code>active</code></td>\n<td>User is currently in the editor/customization flow</td>\n</tr>\n<tr>\n<td><code>completed</code></td>\n<td>User completed checkout, order created</td>\n</tr>\n<tr>\n<td><code>expired</code></td>\n<td>Session expired (24 hours) without completion</td>\n</tr>\n<tr>\n<td><code>cancelled</code></td>\n<td>User cancelled the session</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"session-expiry\">Session Expiry</h2>\n<ul>\n<li><p><strong>Redirect URL:</strong> 15 minutes from creation</p>\n</li>\n<li><p><strong>Active session:</strong> 24 hours after first access</p>\n</li>\n</ul>\n<h2 id=\"available-endpoints\">Available Endpoints</h2>\n<ul>\n<li><strong>POST</strong> Create Session - Partner creates new session</li>\n</ul>\n","_postman_id":"f5b7ef89-3f8a-4c6f-88fc-001cbf2f467f","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","name":"Printora Partner API","type":"collection"}}},{"name":"Order","item":[{"name":"List","id":"43806f30-db94-40ac-9261-99040554bd9a","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"/api/v1/partners/orders?limit=10","description":"<h1 id=\"get-partner-orders\">Get Partner Orders</h1>\n<p>Retrieves a list of all orders created through partner sessions. Orders are sorted by creation date (newest first).</p>\n<hr />\n<h2 id=\"🔍-query-parameters\">🔍 Query Parameters</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Required</th>\n<th>Default</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td>❌ Optional</td>\n<td><code>20</code></td>\n<td>Number of orders to return (max: 100)</td>\n</tr>\n<tr>\n<td><code>offset</code></td>\n<td>integer</td>\n<td>❌ Optional</td>\n<td><code>0</code></td>\n<td>Number of orders to skip for pagination</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>string</td>\n<td>❌ Optional</td>\n<td>-</td>\n<td>Filter by order status (e.g., <code>pending</code>, <code>paid</code>, <code>shipped</code>, <code>delivered</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"status-values\">Status Values</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pending</code></td>\n<td>Order created, awaiting payment</td>\n</tr>\n<tr>\n<td><code>paid</code></td>\n<td>Payment confirmed</td>\n</tr>\n<tr>\n<td><code>processing</code></td>\n<td>Order in production</td>\n</tr>\n<tr>\n<td><code>shipped</code></td>\n<td>Order shipped to customer</td>\n</tr>\n<tr>\n<td><code>delivered</code></td>\n<td>Order delivered</td>\n</tr>\n<tr>\n<td><code>cancelled</code></td>\n<td>Order cancelled</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"📤-response-fields\">📤 Response Fields</h2>\n<h3 id=\"success-response-200-ok\">Success Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"orders\": [...],\n    \"pagination\": {...}\n  }\n}\n\n</code></pre>\n<h4 id=\"order-object\">Order Object</h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>string (UUID)</td>\n<td>Unique order identifier</td>\n</tr>\n<tr>\n<td><code>orderNumber</code></td>\n<td>string</td>\n<td>Human-readable order number (e.g., <code>PRT-1738234567890-ABC123</code>)</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>string</td>\n<td>Current order status</td>\n</tr>\n<tr>\n<td><code>totalAmount</code></td>\n<td>number</td>\n<td>Total order amount</td>\n</tr>\n<tr>\n<td><code>currency</code></td>\n<td>string</td>\n<td>Currency code (e.g., <code>USD</code>)</td>\n</tr>\n<tr>\n<td><code>source</code></td>\n<td>string</td>\n<td>Always <code>\"partner\"</code> for partner orders</td>\n</tr>\n<tr>\n<td><code>partnershipHistoryId</code></td>\n<td>string (UUID)</td>\n<td>Session ID that created this order</td>\n</tr>\n<tr>\n<td><code>createdAt</code></td>\n<td>string (ISO 8601)</td>\n<td>Order creation timestamp</td>\n</tr>\n<tr>\n<td><code>updatedAt</code></td>\n<td>string (ISO 8601)</td>\n<td>Last update timestamp</td>\n</tr>\n</tbody>\n</table>\n</div><h4 id=\"pagination-object\">Pagination Object</h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>total</code></td>\n<td>integer</td>\n<td>Total number of orders matching filter</td>\n</tr>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td>Number of orders returned in this response</td>\n</tr>\n<tr>\n<td><code>offset</code></td>\n<td>integer</td>\n<td>Number of orders skipped</td>\n</tr>\n<tr>\n<td><code>hasMore</code></td>\n<td>boolean</td>\n<td>Whether more orders are available</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"💡-example-use-cases\">💡 Example Use Cases</h2>\n<h3 id=\"pagination-example\">Pagination Example</h3>\n<p><strong>Get first page (20 orders):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/orders?limit=20&amp;offset=0\n\n</code></pre><p><strong>Get second page:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/orders?limit=20&amp;offset=20\n\n</code></pre><p><strong>Get third page:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/orders?limit=20&amp;offset=40\n\n</code></pre><h3 id=\"filter-by-status\">Filter by Status</h3>\n<p><strong>Get only paid orders:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/orders?status=paid\n\n</code></pre><p><strong>Get only shipped orders:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/orders?status=shipped&amp;limit=50\n\n</code></pre><hr />\n<h2 id=\"⚠️-error-responses\">⚠️ Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>401</td>\n<td><code>INVALID_API_KEY</code></td>\n<td>Partner API key is invalid or revoked</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>VALIDATION_ERROR</code></td>\n<td>Invalid query parameters (e.g., limit &gt; 100)</td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>RATE_LIMIT_EXCEEDED</code></td>\n<td>Too many requests</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h2 id=\"🔗-related-endpoints\">🔗 Related Endpoints</h2>\n<ul>\n<li><p><code>POST /api/v1/partner-session</code> - Create session that generates orders</p>\n</li>\n<li><p><code>GET /api/v1/partners/webhook-logs</code> - View webhook notifications for orders</p>\n</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","name":"Printora Partner API","type":"collection"}},"urlObject":{"path":["api","v1","partners","orders"],"host":[""],"query":[{"key":"limit","value":"10"}],"variable":[]}},"response":[],"_postman_id":"43806f30-db94-40ac-9261-99040554bd9a"}],"id":"5f63426b-9438-43e3-a627-afff4ea0dd08","_postman_id":"5f63426b-9438-43e3-a627-afff4ea0dd08","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","name":"Printora Partner API","type":"collection"}}},{"name":"Webhook","item":[{"name":"Logs","id":"ab653ddc-cae2-4871-a085-ccfbeb49e2ce","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"url":"/api/v1/partners/webhook-logs?limit=10","description":"<h1 id=\"get-webhook-logs\">Get Webhook Logs</h1>\n<p>Retrieves webhook delivery logs for all events sent to your partner webhook endpoint. Useful for debugging webhook deliveries and viewing failed notifications.</p>\n<h2 id=\"🔍-query-parameters\">🔍 Query Parameters</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Required</th>\n<th>Default</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td>❌ Optional</td>\n<td><code>20</code></td>\n<td>Number of logs to return (max: 100)</td>\n</tr>\n<tr>\n<td><code>offset</code></td>\n<td>integer</td>\n<td>❌ Optional</td>\n<td><code>0</code></td>\n<td>Number of logs to skip for pagination</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>string</td>\n<td>❌ Optional</td>\n<td>-</td>\n<td>Filter by delivery status</td>\n</tr>\n<tr>\n<td><code>event_type</code></td>\n<td>string</td>\n<td>❌ Optional</td>\n<td>-</td>\n<td>Filter by event type (e.g., <code>order.created</code>, <code>order.paid</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"delivery-status-values\">Delivery Status Values</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pending</code></td>\n<td>Webhook queued, not yet sent</td>\n</tr>\n<tr>\n<td><code>sent</code></td>\n<td>Webhook successfully delivered</td>\n</tr>\n<tr>\n<td><code>failed</code></td>\n<td>Webhook delivery failed</td>\n</tr>\n<tr>\n<td><code>retrying</code></td>\n<td>Webhook is being retried</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"event-type-values\">Event Type Values</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Event Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>order.created</code></td>\n<td>New order created</td>\n</tr>\n<tr>\n<td><code>order.paid</code></td>\n<td>Order payment confirmed</td>\n</tr>\n<tr>\n<td><code>order.shipped</code></td>\n<td>Order shipped to customer</td>\n</tr>\n<tr>\n<td><code>order.delivered</code></td>\n<td>Order delivered to customer</td>\n</tr>\n<tr>\n<td><code>order.cancelled</code></td>\n<td>Order cancelled</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h2 id=\"📤-response-fields\">📤 Response Fields</h2>\n<h3 id=\"success-response-200-ok\">Success Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"logs\": [...],\n    \"pagination\": {...}\n  }\n}\n\n</code></pre>\n<h4 id=\"webhook-log-object\">Webhook Log Object</h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>string (UUID)</td>\n<td>Unique log identifier</td>\n</tr>\n<tr>\n<td><code>eventType</code></td>\n<td>string</td>\n<td>Event type (e.g., <code>order.created</code>)</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>string</td>\n<td>Delivery status (<code>pending</code>, <code>sent</code>, <code>failed</code>, <code>retrying</code>)</td>\n</tr>\n<tr>\n<td><code>httpStatusCode</code></td>\n<td>integer</td>\n<td>HTTP status code from webhook endpoint (e.g., <code>200</code>, <code>500</code>)</td>\n</tr>\n<tr>\n<td><code>attemptCount</code></td>\n<td>integer</td>\n<td>Number of delivery attempts</td>\n</tr>\n<tr>\n<td><code>lastAttemptAt</code></td>\n<td>string (ISO 8601)</td>\n<td>Timestamp of last delivery attempt</td>\n</tr>\n<tr>\n<td><code>nextRetryAt</code></td>\n<td>string (ISO 8601)</td>\n<td>When next retry will occur (if retrying)</td>\n</tr>\n<tr>\n<td><code>responseData</code></td>\n<td>object</td>\n<td>Response body from webhook endpoint</td>\n</tr>\n<tr>\n<td><code>errorMessage</code></td>\n<td>string</td>\n<td>Error message if delivery failed</td>\n</tr>\n<tr>\n<td><code>orderId</code></td>\n<td>string (UUID)</td>\n<td>Associated order ID</td>\n</tr>\n<tr>\n<td><code>partnershipHistoryId</code></td>\n<td>string (UUID)</td>\n<td>Associated session ID</td>\n</tr>\n<tr>\n<td><code>createdAt</code></td>\n<td>string (ISO 8601)</td>\n<td>Log creation timestamp</td>\n</tr>\n</tbody>\n</table>\n</div><h4 id=\"pagination-object\">Pagination Object</h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>total</code></td>\n<td>integer</td>\n<td>Total number of logs matching filter</td>\n</tr>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td>Number of logs returned in this response</td>\n</tr>\n<tr>\n<td><code>offset</code></td>\n<td>integer</td>\n<td>Number of logs skipped</td>\n</tr>\n<tr>\n<td><code>hasMore</code></td>\n<td>boolean</td>\n<td>Whether more logs are available</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"💡-example-use-cases\">💡 Example Use Cases</h2>\n<h3 id=\"get-recent-failed-webhooks\">Get Recent Failed Webhooks</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/webhook-logs?status=failed&amp;limit=20\n\n</code></pre><h3 id=\"get-all-webhooks-for-specific-order\">Get All Webhooks for Specific Order</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/webhook-logs?event_type=order.created\n\n</code></pre><h3 id=\"get-webhooks-sent-in-last-hour\">Get Webhooks Sent in Last Hour</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/webhook-logs?limit=100\n\n</code></pre><p>(Then filter by timestamp in your application)</p>\n<h3 id=\"pagination-example\">Pagination Example</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code># First 50 logs\nGET /api/v1/partners/webhook-logs?limit=50&amp;offset=0\n# Next 50 logs\nGET /api/v1/partners/webhook-logs?limit=50&amp;offset=50\n\n</code></pre><h2 id=\"🐛-debugging-use-case\">🐛 Debugging Use Case</h2>\n<p><strong>Scenario:</strong> Partner reports they didn't receive webhook for an order.</p>\n<p><strong>Steps to debug:</strong></p>\n<ol>\n<li><p>Call <code>GET /api/v1/partners/webhook-logs?event_type=order.created</code></p>\n</li>\n<li><p>Look for log with <code>orderId</code> matching the order</p>\n</li>\n<li><p>Check <code>status</code>:</p>\n<ul>\n<li><p><code>sent</code> → Webhook was delivered successfully, check partner endpoint</p>\n</li>\n<li><p><code>failed</code> → Check <code>errorMessage</code> for failure reason</p>\n</li>\n<li><p><code>retrying</code> → Webhook will be retried automatically</p>\n</li>\n</ul>\n</li>\n<li><p>Use retry endpoint to manually retry failed webhooks</p>\n</li>\n</ol>\n<h2 id=\"⚠️-error-responses\">⚠️ Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>401</td>\n<td><code>INVALID_API_KEY</code></td>\n<td>Partner API key is invalid or revoked</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>VALIDATION_ERROR</code></td>\n<td>Invalid query parameters (e.g., limit &gt; 100)</td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>RATE_LIMIT_EXCEEDED</code></td>\n<td>Too many requests</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h2 id=\"🔗-related-endpoints\">🔗 Related Endpoints</h2>\n<ul>\n<li><p><code>POST /api/v1/partners/webhook-logs/resend</code> - Manually resend a webhook</p>\n</li>\n<li><p><code>POST /api/v1/partners/webhook-logs/:webhookLogId/retry</code> - Retry a failed webhook</p>\n</li>\n<li><p><code>GET /api/v1/partners/orders</code> - Get orders that generated these webhooks</p>\n</li>\n</ul>\n","urlObject":{"path":["api","v1","partners","webhook-logs"],"host":[""],"query":[{"key":"limit","value":"10"}],"variable":[]}},"response":[],"_postman_id":"ab653ddc-cae2-4871-a085-ccfbeb49e2ce"},{"name":"Resend","id":"f483f6a9-ac90-4058-9984-ba66c3080811","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"orderId\": \"84a3e710-c532-4d09-9b89-e41e80337eab\",\r\n  \"eventType\": \"order.paid\"\r\n}","options":{"raw":{"language":"json"}}},"url":"/api/v1/partners/webhook-logs/resend","description":"<h1 id=\"resend-webhook\">Resend Webhook</h1>\n<p>Manually resend a webhook notification for a specific order or session. Useful for retrying failed webhooks or resending notifications for testing.</p>\n<hr />\n<h2 id=\"📥-request-body-parameters\">📥 Request Body Parameters</h2>\n<p><strong>sessionId</strong> (string, UUID, optional)</p>\n<ul>\n<li><p>Session ID that created the order</p>\n</li>\n<li><p>Use this if you don't know the order ID</p>\n</li>\n</ul>\n<p><strong>orderId</strong> (string, UUID, optional)</p>\n<ul>\n<li><p>Order ID to resend webhook for</p>\n</li>\n<li><p>Use this if you know the order ID</p>\n</li>\n</ul>\n<p><strong>eventType</strong> (string, required)</p>\n<ul>\n<li><p>Type of event to resend</p>\n</li>\n<li><p>Must be one of: <code>order.created</code>, <code>order.paid</code>, <code>order.shipped</code>, <code>order.delivered</code></p>\n</li>\n</ul>\n<hr />\n<h2 id=\"⚠️-validation-rules\">⚠️ Validation Rules</h2>\n<ul>\n<li><p>Exactly ONE of <code>sessionId</code> OR <code>orderId</code> must be provided</p>\n</li>\n<li><p>Both cannot be provided together</p>\n</li>\n<li><p><code>eventType</code> is always required</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"📤-response-fields\">📤 Response Fields</h2>\n<h3 id=\"success-response-200-ok\">Success Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"webhookLogId\": \"uuid\",\n    \"eventType\": \"order.created\",\n    \"status\": \"pending\",\n    \"message\": \"Webhook queued for delivery\"\n  }\n}\n\n</code></pre>\n<h2 id=\"💡-example-use-cases\">💡 Example Use Cases</h2>\n<h3 id=\"resend-order-created-webhook-by-session-id\">Resend Order Created Webhook by Session ID</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{\n  \"sessionId\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"eventType\": \"order.created\"\n}\n\n</code></pre><h3 id=\"resend-order-paid-webhook-by-order-id\">Resend Order Paid Webhook by Order ID</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{\n  \"orderId\": \"ord_abc123\",\n  \"eventType\": \"order.paid\"\n}\n\n</code></pre><h3 id=\"resend-order-shipped-webhook\">Resend Order Shipped Webhook</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{\n  \"orderId\": \"ord_abc123\",\n  \"eventType\": \"order.shipped\"\n}\n\n</code></pre><h2 id=\"🐛-use-case-debugging-failed-webhook\">🐛 Use Case: Debugging Failed Webhook</h2>\n<p><strong>Scenario:</strong> Partner reports they didn't receive <code>order.created</code> webhook for a session.</p>\n<p><strong>Steps:</strong></p>\n<ol>\n<li><p>Check logs: <code>GET /api/v1/partners/webhook-logs?event_type=order.created</code></p>\n</li>\n<li><p>Find the log with matching <code>partnershipHistoryId</code></p>\n</li>\n<li><p>{ \"sessionId\": \"session-uuid-from-logs\", \"eventType\": \"order.created\"}</p>\n</li>\n<li><p>Check logs again to confirm webhook was sent</p>\n</li>\n</ol>\n<h2 id=\"⚠️-error-responses\">⚠️ Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>400</td>\n<td><code>VALIDATION_ERROR</code></td>\n<td>Neither sessionId nor orderId provided, or both provided</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>VALIDATION_ERROR</code></td>\n<td>Invalid eventType value</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>ORDER_NOT_FOUND</code></td>\n<td>Order not found or does not belong to this partner</td>\n</tr>\n<tr>\n<td>401</td>\n<td><code>INVALID_API_KEY</code></td>\n<td>Partner API key is invalid or revoked</td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>RATE_LIMIT_EXCEEDED</code></td>\n<td>Too many requests</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h2 id=\"🔗-related-endpoints\">🔗 Related Endpoints</h2>\n<ul>\n<li><p><code>GET /api/v1/partners/webhook-logs</code> - View webhook delivery logs</p>\n</li>\n<li><p><code>POST /api/v1/partners/webhook-logs/:webhookLogId/retry</code> - Retry specific failed webhook</p>\n</li>\n<li><p><code>GET /api/v1/partners/orders</code> - Get orders to find order IDs</p>\n</li>\n</ul>\n","urlObject":{"path":["api","v1","partners","webhook-logs","resend"],"host":[""],"query":[],"variable":[]}},"response":[],"_postman_id":"f483f6a9-ac90-4058-9984-ba66c3080811"},{"name":"Retry","id":"7da79e49-731e-4127-823f-7649a1660a0c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"/api/v1/partners/webhook-logs/:webhookLogId/retry","description":"<h1 id=\"retry-failed-webhook\">Retry Failed Webhook</h1>\n<p>Retry a specific failed webhook delivery using the webhook log ID. This endpoint will attempt to redeliver the webhook to your endpoint.</p>\n<hr />\n<h2 id=\"🎯-when-to-use-this-endpoint\">🎯 When to Use This Endpoint</h2>\n<p>Use this endpoint when:</p>\n<ul>\n<li><p>Webhook delivery failed (status: <code>failed</code>)</p>\n</li>\n<li><p>Webhook is in retry loop (status: <code>retrying</code>)</p>\n</li>\n<li><p>You want to immediately retry instead of waiting for automatic retry</p>\n</li>\n</ul>\n<p><strong>Note:</strong> Do not use this endpoint for webhooks with status <code>sent</code> (already successful).</p>\n<hr />\n<h2 id=\"📥-url-parameters\">📥 URL Parameters</h2>\n<p><strong>webhookLogId</strong> (string, UUID, required)</p>\n<ul>\n<li><p>The unique identifier of the webhook log entry</p>\n</li>\n<li><p>Obtain this from <code>GET /api/v1/partners/webhook-logs</code> response</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"📤-response-fields\">📤 Response Fields</h2>\n<h3 id=\"success-response-200-ok---retry-queued\">Success Response (200 OK) - Retry Queued</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"webhookLogId\": \"uuid\",\n    \"eventType\": \"order.created\",\n    \"status\": \"pending\",\n    \"message\": \"Webhook queued for retry\"\n  }\n}\n\n</code></pre>\n<h3 id=\"success-response-200-ok---already-sent\">Success Response (200 OK) - Already Sent</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"webhookLogId\": \"uuid\",\n    \"eventType\": \"order.created\",\n    \"status\": \"sent\",\n    \"message\": \"Webhook already successfully delivered\"\n  }\n}\n\n</code></pre>\n<h3 id=\"error-response-404---not-found\">Error Response (404 - Not Found)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"WEBHOOK_NOT_FOUND\",\n    \"message\": \"Webhook log not found\"\n  }\n}\n\n</code></pre>\n<h2 id=\"💡-example-use-cases\">💡 Example Use Cases</h2>\n<h3 id=\"retry-a-failed-webhook\">Retry a Failed Webhook</h3>\n<p><strong>Step 1:</strong> Get webhook logs</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/webhook-logs?status=failed\n\n</code></pre><p><strong>Step 2:</strong> Find the log ID from response</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"logs\": [\n    {\n      \"id\": \"log-abc123\",\n      \"eventType\": \"order.created\",\n      \"status\": \"failed\",\n      \"errorMessage\": \"Connection timeout\"\n    }\n  ]\n}\n\n</code></pre>\n<p><strong>Step 3:</strong> Retry using the log ID</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST /api/v1/partners/webhook-logs/log-abc123/retry\n\n</code></pre><p><strong>Step 4:</strong> Check logs again to confirm success</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /api/v1/partners/webhook-logs?event_type=order.created\n\n</code></pre><h2 id=\"🔄-difference-from-resend-endpoint\">🔄 Difference from Resend Endpoint</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Resend Endpoint</th>\n<th>Retry Endpoint</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>URL</strong></td>\n<td><code>/webhook-logs/resend</code></td>\n<td><code>/webhook-logs/:id/retry</code></td>\n</tr>\n<tr>\n<td><strong>Input</strong></td>\n<td><code>sessionId</code> or <code>orderId</code> + <code>eventType</code></td>\n<td><code>webhookLogId</code></td>\n</tr>\n<tr>\n<td><strong>Use Case</strong></td>\n<td>Resend any event for an order/session</td>\n<td>Retry specific failed delivery</td>\n</tr>\n<tr>\n<td><strong>When to Use</strong></td>\n<td>Testing, missed notifications</td>\n<td>Debugging failed deliveries</td>\n</tr>\n<tr>\n<td><strong>Creates New Log</strong></td>\n<td>Yes (new webhook log entry)</td>\n<td>No (updates existing log)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"🐛-debugging-workflow\">🐛 Debugging Workflow</h2>\n<p><strong>Scenario:</strong> Webhook failed to deliver, you want to retry it.</p>\n<p><strong>Complete workflow:</strong></p>\n<ol>\n<li><p>Get failed webhooks: <code>GET /api/v1/partners/webhook-logs?status=failed</code></p>\n</li>\n<li><p>Copy <code>id</code> from the failed log</p>\n</li>\n<li><p>Call retry: <code>POST /api/v1/partners/webhook-logs/{id}/retry</code></p>\n</li>\n<li><p>Wait a few seconds for retry attempt</p>\n</li>\n<li><p>Check logs: <code>GET /api/v1/partners/webhook-logs</code></p>\n</li>\n<li><p>Verify status changed from <code>failed</code> to <code>sent</code> or still <code>failed</code></p>\n</li>\n<li><p>If still failed, check <code>errorMessage</code> for details</p>\n</li>\n</ol>\n<h2 id=\"⚠️-error-responses\">⚠️ Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>404</td>\n<td><code>WEBHOOK_NOT_FOUND</code></td>\n<td>Webhook log not found or doesn't belong to this partner</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>VALIDATION_ERROR</code></td>\n<td>Invalid webhook log ID format</td>\n</tr>\n<tr>\n<td>401</td>\n<td><code>INVALID_API_KEY</code></td>\n<td>Partner API key is invalid or revoked</td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>RATE_LIMIT_EXCEEDED</code></td>\n<td>Too many requests</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"📊-automatic-retry-behavior\">📊 Automatic Retry Behavior</h2>\n<p><strong>Note:</strong> The system automatically retries failed webhooks up to 5 times with exponential backoff:</p>\n<ul>\n<li><p>Retry 1: 1 minute after failure</p>\n</li>\n<li><p>Retry 2: 5 minutes</p>\n</li>\n<li><p>Retry 3: 15 minutes</p>\n</li>\n<li><p>Retry 4: 1 hour</p>\n</li>\n<li><p>Retry 5: 3 hours</p>\n</li>\n</ul>\n<p>Use this endpoint to manually trigger a retry instead of waiting for automatic retry schedule.</p>\n<hr />\n<h2 id=\"🔗-related-endpoints\">🔗 Related Endpoints</h2>\n<ul>\n<li><p><code>GET /api/v1/partners/webhook-logs</code> - View all webhook logs</p>\n</li>\n<li><p><code>POST /api/v1/partners/webhook-logs/resend</code> - Resend webhook (create new log)</p>\n</li>\n<li><p><code>GET /api/v1/partners/orders</code> - Get order information</p>\n</li>\n</ul>\n","urlObject":{"path":["api","v1","partners","webhook-logs",":webhookLogId","retry"],"host":[""],"query":[],"variable":[{"id":"764aeac3-b45f-455c-9db4-48d516725ce2","type":"any","value":"b5334e65-2cd4-4d47-8135-e7b602f98c5d","key":"webhookLogId"}]}},"response":[],"_postman_id":"7da79e49-731e-4127-823f-7649a1660a0c"}],"id":"d6622a58-c667-4108-b234-24d0f7087299","_postman_id":"d6622a58-c667-4108-b234-24d0f7087299","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","id":"a23c6a65-a099-40ab-9208-4f8cc8f6877f","name":"Printora Partner API","type":"collection"}}}],"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]}},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"d4a3b827-da8b-4196-b902-c000e9c34439"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"b65561b7-6164-49ff-89eb-8432f98dc794"}}],"variable":[{"id":"d221bf9a-b283-45f0-b75d-689454ea2a16","key":"url_staging","value":""},{"id":"7073fa74-256b-45fc-8064-084a929f1635","key":"url_prod","value":""},{"id":"c0571795-49ea-47b1-8cca-badfd5a1aa8f","key":"PARTNER_API_KEY","value":""},{"id":"7bab1843-1b44-469e-be02-b47a77d523d3","key":"PARTNER_ID","value":""},{"id":"27336c12-1e11-4c99-bafb-59e7a22adf3c","key":"SESSION_ID","value":""},{"id":"27eaa5d5-6dc1-4a36-9773-0c50f7be7f33","key":"SESSION_TOKEN","value":""}]}