Sportsmarks API
Browse logos, read rulebooks, apply for licenses, submit products and report sales — over REST or MCP. Every capability is one action, exposed identically on both, so anything your agent can do over MCP you can also script over REST.
Authentication
There are two ways in. Either way, a credential always acts as one person in one org, with exactly that person's role and permissions.
A key acts in the org it was created in. If you belong to several orgs, pass X-Org-Id to act in another one you're a member of. Service keys (org-level, not tied to your login staying active) require an Owner/Admin and a human confirmation.
Quickstart: the logos API
Logos are the heart of Sportsmarks: each IP holder's marks, with stable IDs like BYU-0001, colorway variants, rates and license status. With no filters, list_logos returns each institution's primary logo.
# Who am I acting as? curl -H "Authorization: Bearer smk_…" https://sportsmarks.com/api/v1/me # Find a holder, list its logos, download one (URL is good for 10 minutes) curl -H "Authorization: Bearer smk_…" "https://sportsmarks.com/api/v1/holders?q=texas" curl -H "Authorization: Bearer smk_…" "https://sportsmarks.com/api/v1/logos?holder=TAMU" curl -H "Authorization: Bearer smk_…" "https://sportsmarks.com/api/v1/logos/TAMU-001/download"
Lists are paged — follow next_offset when present. Over MCP the same capabilities are the tools search_holders, list_logos, get_logo and download_logo.
Conventions
Reference
Generated from the live action registry — the same registry that serves REST, MCP and the OpenAPI document, so this list can't drift. The MCP tool name equals the action name.
Logos
| Action / MCP tool | REST | Description |
|---|---|---|
| list_logos | GET/api/v1/logos | Logos with ID (e.g. BYU-0002), name, rate, groups, a PNG preview_url, whether you may download the artwork, and variants (the same logo in other colorways, IDs like BYU-0002.v1). With no filters, each holder's primary logo (one per institution). Filter by holder code, q (name or ID text), logo group code, license (a License ID you're party to), or licensed_to_me (brands: logos covered by your Licenses in force) to search all logos; primary=true|false overrides either way. Returns a page (limit, offset) with total and next_offset. full adds download links, colors, usage notes and variant links; for artwork use download_logo.[org.read] |
| get_logo | GET/api/v1/logos/:code | One logo by its permanent ID, e.g. BYU-0002, with its variants.[org.read] |
| download_logo | GET/api/v1/logos/:code/download | The original PNG or SVG of a logo, or of one of its variants (variant: 2 for BYU-0002.v2), for putting on product. Returns a url that downloads the file with no credentials for 10 minutes; inline=true adds the file as base64 instead (large for PNGs). Holders get their own logos; brands get logos a License in force covers, with all their variants. Every download is recorded in your audit log.[org.read] |
| create_logo | POST/api/v1/logos | Upload one logo (PNG + SVG both required, base64-encoded) with a name and its own royalty rate (%). Returns the next permanent ID, e.g. BYU-0003. Optionally add it to existing groups.[logos.manage] |
| update_logo | PATCH/api/v1/logos/:code | Change a logo's name, rate, files, colors, notes, or the groups it's in (group_ids replaces its membership; adding it to a group extends every License granting that group). primary: true makes it your primary logo, the one that stands for you in the catalog; the previous primary steps down. The ID never changes. Rate changes need human confirmation.[logos.manage] |
| retire_logo | POST/api/v1/logos/:code/retire | Retire a logo. It keeps its ID forever so past sales still resolve, but can't be newly granted.[logos.manage] |
| add_logo_variant | POST/api/v1/logos/:code/variants | Add the logo in another colorway (e.g. 'White' for a navy Block Y), as a PNG, an SVG, or both (base64). Variants are optional reference art for licensees: any License that grants the logo covers them, and they aren't approved on their own (product submission approves how they're used). Returns the variant ID, e.g. BYU-0004.v2.[logos.manage] |
| remove_logo_variant | DELETE/api/v1/logos/:code/variants/:variant | Remove one variant of a logo (variant: 2 for BYU-0004.v2). Its number is never reused.[logos.manage] |
| merge_logos | POST/api/v1/logos/:code/merge | Fold logos that are really the same mark in other colorways into one logo: each logo in `merge` becomes a variant of `code` (BYU-0004.v2, named after the merged logo), keeping its PNG and SVG and any variants it had. The merged logos' own IDs stop existing and are never reused; `code` keeps its ID, rate and groups. Only logos nothing relies on yet can be merged: one that is on a License, an application, a product or your rulebook is refused. Needs human confirmation.[logos.manage] |
Logo groups
| Action / MCP tool | REST | Description |
|---|---|---|
| list_logo_groups | GET/api/v1/logo-groups | Logo groups (e.g. BYU-VINTAGE) with rate and member logo IDs. Filter by holder code; holders see their own by default.[org.read] |
| create_logo_group | POST/api/v1/logo-groups | Create a logo group with its own royalty rate, e.g. code VINTAGE → BYU-VINTAGE at 18%. A logo can be in several groups.[logos.manage] |
| update_logo_group | PATCH/api/v1/logo-groups/:code | Rename, re-rate, freeze, or add/remove logo IDs. Adding a logo extends every License that grants this group unless the group is frozen. Rate changes need human confirmation.[logos.manage] |
Holders & rulebooks
| Action / MCP tool | REST | Description |
|---|---|---|
| search_holders | GET/api/v1/holders | IP holders open to licensing, with their code (logo ID prefix), active rulebook summary and fees. Search by q (name or code); returns a page (limit, offset) with total and next_offset. |
| get_rulebook | GET/api/v1/holders/:holder/rulebook | A holder's active rulebook: allowed grants (category × channel × territory with approval mode), open logos, fees, required docs and banned uses. Modes: auto (approved), soft_approve (approved now; the holder may object for soft_approval_window_days), holder_review (a person decides), soft_deny (denied, but you can appeal with appeal_denial), blocked (denied, final). |
| choose_template | POST/api/v1/rulebook/template | Publish a new rulebook version from a template (small_school, governing_body, creator_brand), with optional field changes. Needs human confirmation.[rulebook.edit] |
| update_rulebook | PATCH/api/v1/rulebook | Publish a new rulebook version by changing fields of the active one (e.g. license_approval, default_royalty_rate, grants_allowed). Each rule's mode is one of auto (hard approval), soft_approve (approved now; you can object for soft_approval_window_days), holder_review, soft_deny (denied by default; the brand may appeal to you) or blocked (hard denial). Rulebook versions are immutable. Needs human confirmation unless delegated to agents.[rulebook.edit] |
| get_brand_kit | GET/api/v1/holders/:holder/brand-kit | Everything a licensor licenses out, in one call: logos (with PNG preview_url), phrases and taglines (their words), the groups they belong to, each one's royalty rate, the licensor's colors (hex, Pantone) and its usage guidelines. Brands also see licensed_to_you per mark. A kit the licensor made public is also readable with no sign-in at GET /api/v1/public/kits/<slug> and on the page public_url.[org.read] |
Applications & licenses
| Action / MCP tool | REST | Description |
|---|---|---|
| create_application | POST/api/v1/applications | Apply to a holder for a License: logo groups and/or logo IDs, channel types and territory groups. No categories needed: the License covers every product class the holder's rulebook allows, and Sportsmarks checks each product's category against the rulebook when it's submitted (pass categories only to ask for a narrower License). The holder's rulebook decides immediately: auto-approved (License issued, awaiting your signature), auto-denied with the failing rule IDs, or sent to the holder for review.[licenses.apply] |
| list_applications | GET/api/v1/applications | Holders: applications to you (filter status=holder_review for your review queue). Brands: your applications.[org.read] |
| get_application | GET/api/v1/applications/:id | One application with its rule checks and resulting License, if any.[org.read] |
| decide_application | POST/api/v1/applications/:id/decide | Holder's manual decision on an application in holder_review. Approving issues the License. Needs human confirmation.[licenses.decide] |
| list_licenses | GET/api/v1/licenses | Holders: Licenses granted to brands. Brands: Licenses you hold.[org.read] |
| get_license | GET/api/v1/licenses/:id | One License with its logo access, scope, term, rate overrides and a short-lived agreement PDF link.[org.read] |
| sign_license | POST/api/v1/licenses/:id/sign | Sign a License awaiting signature. Always returns a preview and confirm link: a brand Owner must confirm in the browser. Sportsmarks then countersigns as the holder's agent and the License becomes active.[licenses.sign] |
| withdraw_application | POST/api/v1/applications/:id/withdraw | Take back a License application that hasn't been decided yet (draft or waiting for the holder's review).[licenses.apply] |
| suspend_license | POST/api/v1/licenses/:id/suspend | Pause an active License (e.g. unpaid royalties, an expired insurance certificate). While suspended, new products are denied and sales made from now on are charged at your maximum rate and flagged; sales made before stay licensed. Undo with reinstate_license. The brand sees the reason.[licenses.decide] |
| reinstate_license | POST/api/v1/licenses/:id/reinstate | Put a suspended License back in force. Sales made while it was suspended count as licensed again.[licenses.decide] |
| terminate_license | POST/api/v1/licenses/:id/terminate | End a License for good. Sales made from now on are unlicensed (charged at your maximum rate and flagged); sales made before stay licensed and royalties already owed stay owed. The brand may apply again. This can't be undone.[licenses.decide] |
| propose_amendment | POST/api/v1/licenses/:license_id/amendments | Propose a change to a signed License: renew it (renew: true), add logos or logo groups, change its channels or territories, set negotiated rates (rate_overrides) or move its end date. Nothing changes until the brand accepts (accept_amendment); one open proposal per License. Works on an active License, or an expired one to renew it.[licenses.decide] |
Products
| Action / MCP tool | REST | Description |
|---|---|---|
| submit_product_mockup | POST/api/v1/products | Submit a product once with every logo ID on it (may span holders, e.g. UTAH-0001 + BYU-0002), its channels, the storefronts it will be listed on, and one SKU per variant. Either pass from_store (a product from list_store_products: its title, variants, SKUs and images fill in from your store) or pass images (base64 mockups) and variants yourself. Each SKU can belong to only one product. Sportsmarks checks the images, assigns the product its category from the title, product type, tags, description and images (pass category_hint only if those don't say what it is), creates one claim per holder and evaluates each against that holder's rulebook. Missing Licenses are drafted as bundled applications.[products.submit] |
| update_product | PATCH/api/v1/products/:id | Change a product's declared logo IDs, images, title or description (product_type, tags, category_hint: Sportsmarks re-categorizes it), channels, storefronts or variants and resubmit it. Use it to add an undeclared logo, drop a holder's marks, or fix what a holder flagged. To add a new size, pass add_variants: approvals stay as they are. A new look (color, design, material) of an approved product is refused (409): submit it as a colorway (submit_product_mockup with parent_product_id and look) so the holder sees its mockup. Claims already approved for an unchanged set of logos and unchanged images stay approved.[products.submit] |
| list_products | GET/api/v1/products | Brands: your products with their overall status. Filter by status (awaiting_license, pending, approved, denied, blocked).[org.read] |
| get_product_status | GET/api/v1/products/:id | A product with its per-holder claim status. Brands see every claim, rate and holder note. A holder sees the product, the names of co-holders and the overall status, plus only its own claim.[org.read] |
| confirm_bundled_applications | POST/api/v1/products/:product_id/bundled-applications/confirm | Submit, in one step, the License applications Sportsmarks drafted for every holder on this product you aren't licensed with yet. Each holder's rulebook decides immediately; approved Licenses then need a brand Owner's signature (sign_license).[licenses.apply] |
| appeal_denial | POST/api/v1/products/:product_id/appeal | Ask a person at the holder to look at a product its rulebook denied by default (a claim with can_appeal: true in get_product_status). Say why it should be allowed in note. The claim goes to the holder's review queue; hard denials (blocked categories, logos or scope your License doesn't cover) can't be appealed: fix the product with update_product instead.[products.submit] |
Sales & royalties
| Action / MCP tool | REST | Description |
|---|---|---|
| get_sales_reporting_guide | GET/api/v1/sales/guide | Step-by-step instructions for an agent to report a month of sales: the exact Shopify GraphQL query to run with your own Shopify connector, the formats report_sales and upload_sales_csv accept, and how the period gets attested. Call this first.[org.read] |
| report_sales | POST/api/v1/sales | Send sales lines for any period: format=shopify_orders with raw order nodes from your Shopify connector (GraphQL or REST shape), or format=lines with Sportsmarks lines (wholesale, Amazon, anything else). Each line is matched to an approved SKU and gets one royalty line per holder at the frozen rate; a sale outside a holder's Approval or License is charged at that holder's maximum royalty rate and flagged. Duplicates are ignored. Call get_sales_reporting_guide for the exact query.[sales.report] |
| upload_sales_csv | POST/api/v1/sales/upload | Upload sales as CSV/TSV text: Shopify's order export, Amazon's All Orders report, or the Sportsmarks template (see get_sales_reporting_guide). The format is detected from the header. Same matching, royalty lines and dedupe as report_sales.[sales.report] |
| list_sales_reports | GET/api/v1/sales/reports | Your monthly sales reports (draft or submitted) with totals.[reports.view] |
| get_sales_report | GET/api/v1/sales/reports/:period | One period's sales: totals, royalties per holder, exceptions by rule, how the lines arrived, how many our storefront crawl corroborates, and approved listings that are live with no reported sales.[reports.view] |
| list_sales | GET/api/v1/sales/reports/:period/lines | Sales lines in a period with their retailer and royalty lines; filter to exceptions (status=exception, with the rule that failed) or lines of SKUs declared not licensed (status=excluded).[reports.view] |
| submit_sales_report | POST/api/v1/sales/reports/:period/submit | Attest that a month's sales are complete and accurate and lock the period. Returns a preview with totals per holder; a brand Owner or Finance user confirms it in the browser (agents can't). A month with no sales can be submitted as $0.[sales.report] |
| exclude_skus | POST/api/v1/sales/excluded-skus | Same as declare_not_licensed, by SKU. Declare that SKUs you sold carry no licensed marks (e.g. a plain wallet), so their sales are left out of royalties without an unknown-SKU exception. Stays declared for later months, is shown in each month's attestation, and is audited. A SKU already on one of your products can't be excluded; adding an excluded SKU to a product later undoes it.[sales.report] |
Catalog & links
| Action / MCP tool | REST | Description |
|---|---|---|
| list_channel_variants | GET/api/v1/catalog/variants | The variants of the store products you sync, as each channel knows them (Shopify variants, Amazon seller SKUs, wholesale lines), plus SKUs that appeared on your sales reports, and which of your product variants each one is. Linked automatically when the SKU or barcode matches; otherwise unlinked, with suggestions to confirm (accept_link_suggestions), link by hand (link_variant) or declare not licensed (declare_not_licensed). Unlinked items with sales block submitting that month.[org.read] |
| link_variant | POST/api/v1/catalog/variants/:channel_variant_id/link | Say which of your product variants a channel variant is (e.g. the Amazon seller SKU USAH-TEE-M-AMZ is your Navy Tee, size M). Its sales then count as that product's: its sales in open (draft) months are re-checked (including ones counted under a product it was linked to before), and listings re-matched. Items whose SKU or barcode matches are linked automatically and can't be re-linked here.[products.submit] |
| accept_link_suggestions | POST/api/v1/catalog/suggestions/accept | Link each of these unlinked channel variants to its top suggestion (see list_channel_variants). Items with no suggestion are skipped and reported.[products.submit] |
| unlink_variant | POST/api/v1/catalog/variants/:channel_variant_id/unlink | Undo a link you made (or a not-licensed declaration). Its sales in open (draft) months are re-checked and become exceptions until it's linked again; submitted months don't change. Links made by a matching SKU or barcode can't be undone here: change the product's variants instead.[products.submit] |
| declare_not_licensed | POST/api/v1/catalog/not-licensed | Declare that these channel variants carry no licensed marks (e.g. a plain wallet), so their sales are left out of royalties without an exception. Applies to the SKU everywhere you sell it, stays declared for later months, is shown in each month's attestation, and is audited. Undo with unlink_variant.[sales.report] |
API keys
| Action / MCP tool | REST | Description |
|---|---|---|
| create_api_key | POST/api/v1/api-keys | Create a personal API key for agents and integrations, acting as you in your current org. Optional scopes narrow it to a subset of your permissions. Service keys (service: true) need users.manage and human confirmation. The key is shown once.[org.read] |
| list_api_keys | GET/api/v1/api-keys | Your API keys and connected agents (OAuth, with oauth_client_name) in the current org, and the org's service keys if you are an Owner/Admin. Secrets are never returned.[org.read] |
| revoke_api_key | DELETE/api/v1/api-keys/:id | Revoke one of your API keys or connected agents (or a service key, if you are an Owner/Admin). Takes effect immediately.[org.read] |
Confirmations
| Action / MCP tool | REST | Description |
|---|---|---|
| get_confirmation | GET/api/v1/confirmations/:token | The preview and status of a confirmation token returned by a legal or money action.[org.read] |
| list_pending_confirmations | GET/api/v1/confirmations | Actions in your org waiting for a human to confirm (signatures, rate changes, rulebook publishes, manual approvals).[org.read] |
| confirm_action | POST/api/v1/confirmations/confirm | Execute a previewed action. Legal and money actions need a signed-in human in the browser (agents get 403) unless an Owner delegated that action to agents (get_agent_delegation). Product decisions (decide_review) and delegated actions may be confirmed by the same agent key that requested them.[org.read] |
| decline_action | POST/api/v1/confirmations/decline | Cancel a pending confirmation without executing it.[org.read](browser only) |
Account & org
| Action / MCP tool | REST | Description |
|---|---|---|
| whoami | GET/api/v1/me | The calling user, the org and role this call acts in, its permissions, and every org membership. |
| whats_next | GET/api/v1/whats-next | The next steps for your org right now, each with the action (tool) that does it.[org.read] |
| list_members | GET/api/v1/members | Users in the caller's org with their roles, plus open invites.[org.read] |
| invite_member | POST/api/v1/invites | Invite someone to the org with a role. Emails them a one-time link (also returned as invite_url); only that email can accept it, and accepting creates their account if they don't have one. Inviting an Owner needs human confirmation.[users.manage] |
| accept_invite | POST/api/v1/invites/accept | Join an org using an invite token. The signed-in user's email must match the invite.(browser only) |
| complete_brand_signup | POST/api/v1/signups/:signup_id/complete | After the person confirmed their email from the sign-up link: create the brand and make them its Owner. Only the signed-in person whose email started the sign-up can finish it, in the browser.(browser only) |
| update_member | PATCH/api/v1/members/:user_id | Change a member's role. Making someone an Owner needs human confirmation.[users.manage] |
| remove_member | DELETE/api/v1/members/:user_id | Remove a user from the org. Every API key and agent acting for them in this org stops working immediately.[users.manage] |
| get_taxonomy | GET/api/v1/taxonomy | The shared product classes (categories: apparel, headwear, accessories, home, toys-games, sporting-goods, paper-goods, pet, automotive, with a few subcategories like apparel/tops/t-shirt), channel types and territory groups used by every holder. Licenses and rulebooks work on these classes. Each product also gets an exact Sportsmarks category (search_product_categories) and attributes like age-group, which Sportsmarks assigns when it's submitted; holders' product_exceptions target those. |
| search_product_categories | GET/api/v1/product-categories | Search the Sportsmarks product categories (built from Shopify's open taxonomy v2026-08, plus licensing categories like Replica Jerseys and Pennants), e.g. "t-shirt", "shot glass", "replica jersey". Each result shows its product class (null = not licensable) and whether Sportsmarks added it. Use an id in a rulebook's product_exceptions. You don't need one to submit a product: Sportsmarks categorizes it. |
| list_rulebook_templates | GET/api/v1/rulebook-templates | Template rulebooks a holder can start from: Small School, Governing Body, Creator Brand. |
| update_brand_kit | PATCH/api/v1/brand-kit | Make your brand kit public or private, and set its usage guidelines. Public: anyone can see your marks' names, PNG previews, phrases, colors, rates and guidelines without signing in (a page, and GET /api/v1/public/kits/<slug>). Artwork files stay available only to brands licensed for them.[logos.manage] |
| set_brand_colors | PUT/api/v1/brand-kit/colors | Replace your brand kit's color palette: each color has a name, a hex value, an optional Pantone reference and a role (primary, secondary, accent, neutral). Pass the full list in display order ([] clears it). Licensees and, if your kit is public, anyone can see it.[logos.manage] |
| create_phrase | POST/api/v1/phrases | Add words you license (a phrase, slogan, tagline or nickname, e.g. "Go Utes!") as their own mark with a royalty rate (%). It gets the next permanent ID like a logo (e.g. UTAH-0031), can be put in groups, granted on a License on its own, declared on products, and is looked for on product images by its words. Edit it later with update_logo; retire it with retire_logo.[logos.manage] |
| upload_document | POST/api/v1/documents | Put a document on file for your brand: coi (certificate of insurance), code_of_conduct, w9 or factory_disclosure. Licensors' rulebooks can require these (required_docs) before a License is issued; a missing one auto-denies the application with REQUIRED_DOC_MISSING. PDF, PNG or JPEG, base64, up to 10 MB. Uploading the same kind again replaces it. Pass expires_on (e.g. the policy end date) so it stops counting once it lapses.[licenses.apply] |
| list_documents | GET/api/v1/documents | Documents on file, with short-lived download links. Brands: your own. Licensors: pass brand_id to see the documents of a brand that has applied to you or holds your License.[org.read] |
| remove_document | DELETE/api/v1/documents/:id | Take a document off file. Licenses already issued are unaffected; new applications that require it will be denied until you upload another.[licenses.apply] |
| list_amendments | GET/api/v1/amendments | Amendments and renewals proposed on your Licenses (status=proposed for the ones waiting on the brand).[org.read] |
| accept_amendment | POST/api/v1/amendments/:id/accept | Agree to the licensor's proposed amendment or renewal. The License changes at once and a new agreement PDF is issued. Like signing, a brand Owner confirms it in the browser unless your org delegated it to agents.[licenses.sign] |
| decline_amendment | POST/api/v1/amendments/:id/decline | Turn down the licensor's proposed amendment or renewal. The License stays as it is.[licenses.sign] |
| withdraw_amendment | POST/api/v1/amendments/:id/withdraw | Take back an amendment or renewal you proposed that the brand hasn't accepted yet.[licenses.decide] |
| quote_rate | POST/api/v1/quote-rate | Given the logo IDs on a product (may span holders, e.g. UTAH-0004 + BYU-0002), return each holder's rate and its source under your Licenses, the total stacked rate, and any holders you still need a License from.[org.read] |
| export_audit_log | GET/api/v1/audit-log | Audit entries for your org, newest first: who (user or system), role, channel (ui/rest/mcp), API key, action, target and before/after.[audit.view] |
| add_storefront | POST/api/v1/storefronts | Declare a Shopify or Amazon storefront URL where you sell (e.g. ooopit.com or an Amazon brand store). Returns how to prove ownership: a DNS TXT record or a meta tag.[channels.connect] |
| verify_storefront | POST/api/v1/storefronts/:id/verify | Check the storefront's DNS TXT record or home-page meta tag and mark it verified.[channels.connect] |
| list_storefronts | GET/api/v1/storefronts | Your declared storefronts with their ownership status and verification instructions.[org.read] |
| add_wholesale_account | POST/api/v1/wholesale-accounts | Declare a wholesale buyer (campus store, boutique, distributor…). Buyer details are optional unless a holder's rulebook asks for them.[channels.connect] |
| list_wholesale_accounts | GET/api/v1/wholesale-accounts | Your declared wholesale buyers.[org.read] |
| list_store_products | GET/api/v1/store-products | Products in your Shopify store (read live from its public product feed; nothing is stored) with every variant's SKU, images and a suggested category, whether each is already submitted, whether you sync it, and why we'd recommend syncing it (a variant SKU or barcode is on one of your products, the title looks like one, or it names one of your licensors). status=recommended lists the ones worth syncing, best first: sync them with sync_store_products. Or pick one and pass it to submit_product_mockup as from_store so its title, variants, SKUs and images fill in automatically (that also syncs it). Agents with a Shopify connector can instead pass variants and images directly.[org.read] |
| list_reviews | GET/api/v1/reviews | Your product claims: the products carrying your marks that your rulebook sent to you (status=holder_review, the default), the ones it approved provisionally that you can still object to (status=provisional, with objection_until), or any other status. Shows co-holder names, never their terms.[reports.view] |
| decide_review | POST/api/v1/reviews/:product_id/decide | Your decision on a product claim waiting for you (holder_review), or your objection to one your rulebook approved provisionally (list_reviews status=provisional, until its objection_until). approve freezes the rate on an Approval tied to the product's SKUs (on a provisional approval it ends the objection window early). deny blocks the product. request_changes sends it back to the brand to fix and resubmit; it returns to you afterwards. deny and request_changes show the brand your note; an objection keeps sales made up to now licensed. Returns a preview and confirm_token first; the same agent may then call confirm_action with that token.[products.decide] |
| get_royalty_summary | GET/api/v1/royalties | Royalties by period. Brands: per holder, including draft periods. Holders: per licensee, from submitted reports only, and only your own royalty lines.[reports.view] |
| import_listings | POST/api/v1/listings | Sync the store products you choose (e.g. licensed products from your Shopify admin, Amazon ASINs, wholesale styles): channel, the channel's product ID, title, URL and SKUs, or better its variants (with barcode/ASIN/options). Send only the products you want tracked, not your whole catalog. Each is kept as a listing and its variants on Catalog & links, linked to your product variants by SKU or barcode. One that's live before every holder approved, or has variant SKUs not on the product, raises a flag. Stop syncing one with unsync_listing.[products.submit] |
| crawl_storefront | POST/api/v1/storefronts/:storefront_id/crawl | Re-read a Shopify storefront's public product feed (no credentials) and refresh the products you sync: new variants, removed ones, delisted products. Nothing else in the store is stored; recommended says how many products you don't sync look licensed (see list_store_products). Synced products live before every holder approved, or with variant SKUs not on the product, raise flags; sales of SKUs seen live are marked corroborated. Runs nightly too.[products.submit] |
| sync_store_products | POST/api/v1/storefronts/:storefront_id/sync | Start syncing the store products you choose (by the store's product ID, from list_store_products). Each is kept as a listing, its variants go on Catalog & links (linked to your product variants by SKU or barcode), and from then on it's refreshed nightly and its sales are tracked. Nothing else in the store is synced.[products.submit] |
| unsync_listing | POST/api/v1/listings/:id/unsync | Stop syncing a store product: it's no longer refreshed and its sales from a connected store aren't imported. Its variants that never sold are removed from Catalog & links (ones with sales stay, with their history); its open flags close with that reason. Sync it again any time.[products.submit] |
| list_listings | GET/api/v1/listings | The store products you sync and their status: approved, not_approved (live before every holder approved), unmatched (not linked to one of your products yet: link its variants on Catalog & links) or dismissed.[org.read] |
| dismiss_listing | POST/api/v1/listings/:id/dismiss | Mark a live listing as carrying no licensed marks (e.g. a blank tee), with a reason. Closes its flags; the reason is kept and audited.[products.submit] |
| list_flags | GET/api/v1/flags | Compliance flags: listings live before every holder approved, listings with variant SKUs not on the product, and sales that fail the sales gate. Brands see all of theirs; a holder sees only flags involving its own marks.[reports.view] |
| resolve_flag | POST/api/v1/flags/:id/resolve | Close an open compliance flag on your marks with a note: resolved (dealt with, e.g. you approved the product or settled it with the brand) or dismissed (not a problem). The brand sees the note. The royalty already charged on a flagged sale doesn't change. Flags also close on their own when the cause is fixed.[compliance.flag] |
| list_royalty_lines | GET/api/v1/royalties/:period/lines | Every sale line that owes you a royalty in one month, from reports the brands have submitted: licensee, order, SKU, product, retailer, units, net sales, the rate applied and why, and whether the sale was outside your License (unlicensed, charged at your maximum rate). Only your own royalty lines. Returns a page with total and next_offset.[reports.view] |
| list_statements | GET/api/v1/statements | What brands owe licensors: one royalty statement per month and licensor (issued when the brand's sales report is submitted, net of credits and the unearned advance), plus each License's application fee, annual fees, advance and any minimum-guarantee shortfall. Brands see what they owe; licensors see what they are owed. status: open (owed), processing, paid, failed, credit (a month where refunds exceeded sales; used against later months), applied, void. Open statements are collected by bank debit (ACH) when due, once the brand has authorized a bank account (start_bank_setup) and the licensor has set up payouts (start_payout_setup); see get_payment_setup.[reports.view] |
| get_payment_setup | GET/api/v1/payments/setup | Whether your org is ready for payments. Brands: the bank account authorized for debits (statements are collected by bank debit only; no cards). Licensors: whether the payout account is set up and Stripe can pay you. Says what to do next if not.[reports.view] |
| start_bank_setup | POST/api/v1/payments/bank-setup | Get a link to a Stripe page where a person at your brand links a US bank account and accepts the debit authorization. Statements are then collected from that account automatically when due. Replaces any bank account already on file. Bank accounts only; cards aren't accepted. The link is for the person who asked for it and expires.[statements.pay] |
| start_payout_setup | POST/api/v1/payments/payout-setup | Get a link to Stripe's onboarding where a person at your organization enters its legal details and the bank account royalties are paid to. Run it again to finish or update. The link is for the person who asked for it and expires in minutes.[billing.request] |
| pay_statement | POST/api/v1/statements/:id/pay | Start the bank debit for one open or failed statement now instead of waiting for its due date (open statements are collected automatically when due). The statement is processing until the bank confirms, usually within about four business days. A person confirms it in the browser unless your org delegated it to agents.[statements.pay] |
| list_events | GET/api/v1/events | What happened in your org, oldest first: application.submitted, application.decided, application.withdrawn, license.issued, license.signed, license.status_changed, amendment.proposed, amendment.decided, product.review_needed, product.decided, product.appealed, flag.opened, flag.resolved, sales_report.submitted, rulebook.published, statement.issued, statement.paid, statement.failed. Each event has an id, type, created_at and a small data object with IDs and statuses (fetch detail with the usual actions). Pass after (the last id you saw) to get only newer ones; poll this, or register a webhook (create_webhook) to be told instead.[org.read] |
| create_webhook | POST/api/v1/webhooks | Have Sportsmarks POST your org's events to an https URL as they happen (JSON: id, type, created_at, data). Returns a signing secret once: each request carries a Sportsmarks-Signature header, t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<body>" with the secret>. Answer 2xx within 5 seconds; failures are retried for about two days. Leave event_types empty for every type.[users.manage] |
| list_webhooks | GET/api/v1/webhooks | Your org's webhook endpoints with each one's last deliveries (status, attempts, HTTP status, error).[users.manage] |
| delete_webhook | DELETE/api/v1/webhooks/:id | Stop sending events to a webhook endpoint and remove it.[users.manage] |
| list_orgs | GET/api/v1/admin/orgs | Every holder and brand on Sportsmarks with its members, open invites and whether a rulebook is active.[platform.admin] |
| create_holder_org | POST/api/v1/admin/holders | Create a school, governing body or creator (holder) or an athlete as an IP holder. The code is the permanent logo-ID prefix (BYU → BYU-0001). Then invite its first Owner with invite_org_owner.[platform.admin] |
| set_platform_rate | POST/api/v1/admin/orgs/:org_id/platform-rate | Set Sportsmarks' own terms with one licensor, as negotiated with it: the rate added on top of its royalty (e.g. 2 on a licensor charging 12% means its brands pay 14% of net sales and the licensor keeps 12%) and, optionally, Sportsmarks' own application and annual fees on top of the licensor's. Pass only what changes. Brands see the combined figures. The terms are fixed on each License when it is issued and stated in its agreement, so a change applies to new Licenses and to renewals, not to Licenses already issued. A human confirms it in the browser.[platform.admin] |
| invite_org_owner | POST/api/v1/admin/orgs/:org_id/owner-invites | Invite the first Owner of an IP holder (or the athlete of an athlete holder). They get an email; only that address can accept, and accepting creates their account.[platform.admin] |
| get_agent_delegation | GET/api/v1/agent-delegation | The legal and money actions in your org that normally need a human to confirm in the browser, and which of them an Owner has delegated to agents. A delegated action still returns a preview and confirm_token; the agent that requested it may then confirm it.[org.read] |
| set_agent_delegation | POST/api/v1/agent-delegation | Set the full list of confirm-gated actions your org's agents may complete without a human in the browser (see get_agent_delegation for the choices; pass [] to delegate nothing). Owners only, and always confirmed by a human in the browser.[users.manage] |