{"openapi":"3.1.0","info":{"title":"OF2 Partner API","version":"1.0.0-draft","summary":"Agent-ready collaborator API for affiliates, dropshippers, and approved buyer agents.","description":"Draft contract for the centralized OF2 Partner layer. Endpoints marked x-status=planned are not production write paths yet."},"servers":[{"url":"https://of2.avidan-business-group.com"}],"tags":[{"name":"identity","description":"Identity and access: Collaborator agents authenticate with scoped API keys, idempotency keys, and full audit trails."},{"name":"catalog","description":"Catalog and quote: Agents can search approved catalogs and build compliant quotes without seeing private OF2 data."},{"name":"affiliate","description":"Affiliate links and attribution: Affiliates and their agents can create campaigns, friendly URLs, and monitor conversion."},{"name":"dropship","description":"Dropship orders: Dropshippers can place customer orders, upload CSV batches, and track fulfillment from one API."},{"name":"payments","description":"Commissions and payouts: Collaborators can reconcile money without asking ops for screenshots or manual exports."},{"name":"messages","description":"Messages, notifications, and webhooks: Agents can react to changes in real time instead of polling the Partner PWA."},{"name":"content","description":"Content and SEO distribution: Approved partners can request campaign assets and publish useful content without brand drift."},{"name":"openapi","description":"Machine-readable API manual: Collaborator AIs can discover the contract, schemas, scopes, and future endpoints programmatically."}],"security":[{"partnerApiKey":[]}],"paths":{"/api/partner/v1/me":{"get":{"tags":["identity"],"summary":"Return the collaborator, programs, scopes, allowed sites, and current limits.","description":"Return the collaborator, programs, scopes, allowed sites, and current limits.","x-status":"live","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["live"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/api-keys":{"post":{"tags":["identity"],"summary":"Create or rotate keys from the Partner PWA after human approval.","description":"Create or rotate keys from the Partner PWA after human approval.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/payout-account":{"patch":{"tags":["identity"],"summary":"Submit or update the collaborator's verified IBAN payout account for bank-transfer payouts only.","description":"Submit or update the collaborator's verified IBAN payout account for bank-transfer payouts only.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/catalog":{"get":{"tags":["catalog"],"summary":"Search products by site, locale, market, price tier, availability, and compliance flags.","description":"Search products by site, locale, market, price tier, availability, and compliance flags.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/quotes":{"post":{"tags":["catalog"],"summary":"Create a priced quote with retail/B2B commission rules, VAT checks, website MOQ, shipping, and B2B uplift policy.","description":"Create a priced quote with retail/B2B commission rules, VAT checks, website MOQ, shipping, and B2B uplift policy.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/links":{"post":{"tags":["affiliate"],"summary":"Create friendly URLs and campaign links for approved sites/projects.","description":"Create friendly URLs and campaign links for approved sites/projects.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/attribution":{"get":{"tags":["affiliate"],"summary":"Read clicks, sessions, lifetime-tagged customers, orders, conversion rate, commission status, and content source.","description":"Read clicks, sessions, lifetime-tagged customers, orders, conversion rate, commission status, and content source.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/clients":{"get":{"tags":["affiliate"],"summary":"List only the customers lifetime-attributed to the authenticated collaborator, with revenue and commission rollups.","description":"List only the customers lifetime-attributed to the authenticated collaborator, with revenue and commission rollups.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/clients/{customer_id}":{"get":{"tags":["affiliate"],"summary":"Read one attributed customer profile, repeat-order history, order totals, product summary, and commission summary.","description":"Read one attributed customer profile, repeat-order history, order totals, product summary, and commission summary.","x-status":"planned","parameters":[{"name":"customer_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/clients/{customer_id}/orders":{"get":{"tags":["affiliate"],"summary":"Read the attributed customer's order history, ordered products, order value, and collaborator commission per order.","description":"Read the attributed customer's order history, ordered products, order value, and collaborator commission per order.","x-status":"planned","parameters":[{"name":"customer_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/links/{link_id}/discount":{"patch":{"tags":["affiliate"],"summary":"Allocate part of the approved retail 25% partner pool as a customer-facing discount and keep the rest as commission.","description":"Allocate part of the approved retail 25% partner pool as a customer-facing discount and keep the rest as commission.","x-status":"planned","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/dropship/orders":{"post":{"tags":["dropship"],"summary":"Create one dropship order with shipping address, products, customer reference, site MOQ/shipping validation, and retail/B2B margin policy.","description":"Create one dropship order with shipping address, products, customer reference, site MOQ/shipping validation, and retail/B2B margin policy.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/dropship/imports":{"post":{"tags":["dropship"],"summary":"Upload or submit batch orders with validation results before commit.","description":"Upload or submit batch orders with validation results before commit.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/orders/{order_id}":{"get":{"tags":["dropship"],"summary":"Read status, tracking, invoices, incidents, payments, and collaborator-visible notes.","description":"Read status, tracking, invoices, incidents, payments, and collaborator-visible notes.","x-status":"planned","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/commissions":{"get":{"tags":["payments"],"summary":"Read pending, approved, disputed, and paid commission ledger entries.","description":"Read pending, approved, disputed, and paid commission ledger entries.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/payouts":{"get":{"tags":["payments"],"summary":"Read IBAN bank-transfer payout batches, status, tax/VAT notes, and remittance documents.","description":"Read IBAN bank-transfer payout batches, status, tax/VAT notes, and remittance documents.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/messages":{"get":{"tags":["messages"],"summary":"Read collaborator-visible OF2 messages and system notices.","description":"Read collaborator-visible OF2 messages and system notices.","x-status":"live","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["live"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}},"post":{"tags":["messages"],"summary":"Send a collaborator dashboard/API message into OF2 Ops.","description":"Send a collaborator dashboard/API message into OF2 Ops.","x-status":"live","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["live"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/webhooks":{"post":{"tags":["messages"],"summary":"Register webhook targets for order, tracking, payout, link, approval, and API-key events.","description":"Register webhook targets for order, tracking, payout, link, approval, and API-key events.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/notifications/subscribe":{"post":{"tags":["messages"],"summary":"Register PWA push subscriptions for collaborator users and approved agent owners.","description":"Register PWA push subscriptions for collaborator users and approved agent owners.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/content/briefs":{"get":{"tags":["content"],"summary":"Read campaign briefs, allowed claims, blocked claims, keywords, image rules, target URLs, and lifetime-attribution SEO messaging.","description":"Read campaign briefs, allowed claims, blocked claims, keywords, image rules, target URLs, and lifetime-attribution SEO messaging.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/content/drafts":{"post":{"tags":["content"],"summary":"Submit partner/agent content drafts for review, tracking, and SEO attribution.","description":"Submit partner/agent content drafts for review, tracking, and SEO attribution.","x-status":"planned","parameters":[],"responses":{"200":{"description":"Planned response shape.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["planned"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}},"/api/partner/v1/openapi":{"get":{"tags":["openapi"],"summary":"Return the current Partner API v1 OpenAPI contract.","description":"Return the current Partner API v1 OpenAPI contract.","x-status":"live","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["live"]},"data":{"type":"object"}},"required":["ok","status"]}}}},"401":{"description":"Missing or invalid partner API key."},"403":{"description":"Scope, site, channel, or program is not allowed."},"409":{"description":"Duplicate idempotency key or conflicting order/customer reference."},"429":{"description":"Rate limit exceeded."}}}}},"components":{"securitySchemes":{"partnerApiKey":{"type":"apiKey","in":"header","name":"Authorization","description":"Use: Bearer of2_partner_live_xxx or Bearer of2_partner_test_xxx"}},"parameters":{"idempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Required for write endpoints that create links, quotes, orders, imports, content drafts, or webhooks."}},"schemas":{"ApiError":{"type":"object","properties":{"ok":{"type":"boolean","const":false},"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}},"required":["ok","code","message","request_id"]}}},"x-partner-scopes":["partner:read","catalog:read","quote:create","affiliate:links","attribution:read","clients:read","dropship:order","orders:read","commissions:read","payouts:read","payouts:write","messages:read","messages:write","notifications:write","webhooks:write","content:read","content:submit"],"x-rollout":[{"phase":"Foundation","outcome":"Publish the PWA manual, OpenAPI contract, scopes, auth model, idempotency rules, and endpoint map."},{"phase":"Read-only data","outcome":"Ship me, catalog, links, lifetime attribution, attributed clients, client order history, commissions, IBAN payout status, and messages as safe read endpoints."},{"phase":"Controlled writes","outcome":"Enable quote creation, link creation, collaborator discount allocation, IBAN payout account submission, dropship order drafts, content draft submission, and webhook registration."},{"phase":"Automation","outcome":"Enable agent API keys, rate limits, webhooks, PWA push events, audit logs, and partner-facing incident states."},{"phase":"Public growth","outcome":"Publish SEO pages for affiliate program, dropship program, and agent API partnership without exposing private OF2."}],"x-business-rules":[{"id":"iban_only_payouts","title":"IBAN bank-transfer payouts only","rule":"Collaborator payouts are paid by bank transfer to a verified IBAN account. No PayPal, card payout, crypto, wallet, or informal payment method is part of the production model.","implementation":"Collect payout account holder, IBAN country, IBAN last4, verification status, and encrypted IBAN payload before any payout batch can be approved."},{"id":"retail_25_pool","title":"Retail programs use a 25% partner pool","rule":"Retail affiliate/dropship programs start from a 25% partner pool against retail price. The collaborator can keep it as commission or pass part of it forward as a customer discount.","implementation":"Link and quote creation must carry collaborator_discount_percent and collaborator_commission_percent, with their sum capped at the approved retail partner pool."},{"id":"website_rules_always_apply","title":"Website MOQ and shipping rules always apply","rule":"Every collaborator order respects the minimum order, shipping cost, taxes, market restrictions, and checkout rules of the website that owns the order.","implementation":"Quote and dropship-order validation must evaluate site MOQ and shipping policy before the order can become payable or fulfillable."},{"id":"lifetime_attribution","title":"Lifetime customer attribution","rule":"A customer first brought by an affiliate is tagged to that affiliate for life. OF2 does not play 30/60/90-day cookie games for payable attribution.","implementation":"The first accepted affiliate attribution creates a durable customer-site-collaborator record. Later cookie/session data can enrich source analytics but cannot silently steal the customer."},{"id":"b2b_margin_policy","title":"B2B/wholesale needs a separate margin policy","rule":"Wholesale and B2B websites cannot use the same retail 25% rule because tier pricing, tariff discounts, MOQ, and shipping economics are different.","implementation":"For B2B dropship orders below normal MOQ, quote from wholesale base plus an approved uplift/margin policy, plus shipping. The first working placeholder is wholesale price + 30% until Adam finalizes per-site rules."},{"id":"partner_client_transparency","title":"Read-only client and order transparency","rule":"Collaborators can see the customers attributed to them, those customers' order history, products ordered, repeat orders, and commission generated per order. They cannot see unrelated customers.","implementation":"Partner client/order endpoints are read-only, scoped to lifetime attribution records, and do not allow collaborator-to-customer messaging or customer data edits."}]}