{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"OpenAffiliate REST API","version":"1.0.0","description":"Search the public affiliate program registry and read program terms. No authentication or API key is required. The only write is POST /api/submissions, which queues a program for a maintainer to verify; it never lists or scores anything by itself. Versioning: every response carries an API-Version header, currently 1, and a request may send API-Version: 1 to pin it (any other value returns 400 UNSUPPORTED_API_VERSION). Breaking changes ship only under a new major version; additive changes (new fields, parameters or endpoints) can arrive in the current one. Deprecation: a field, parameter or endpoint is deprecated at least 90 days before it is removed. Its responses then carry a Deprecation header (RFC 9745) with the date it was deprecated and a Sunset header (RFC 8594) with the date it stops working, and the change is listed in the changelog at https://openaffiliate.dev/changelog."},"servers":[{"url":"https://openaffiliate.dev"}],"paths":{"/api/programs":{"get":{"operationId":"searchPrograms","summary":"Search affiliate programs","description":"Search active programs. Returns a programs array, total before pagination and applied filters. Unverified terms are omitted or empty. Nothing in the query is rejected, so older clients keep working: unknown parameters are ignored (tracking parameters are fine), a repeated parameter uses its first value, an unknown sort falls back to relevance (legacy sort=new means newest), a non-boolean verified does not filter, limit and offset are read as a leading integer (so 1x reads as 1; text with no leading digits or a negative offset counts as 0), and an unknown type or category simply matches nothing.","parameters":[{"name":"API-Version","in":"header","required":false,"description":"Pin the API major version. Omitted means the current version, 1. Any other value returns 400 UNSUPPORTED_API_VERSION.","schema":{"type":"string","enum":["1"],"default":"1"}},{"name":"q","in":"query","required":false,"description":"Search keywords. Empty means all active programs.","schema":{"type":"string","default":""}},{"name":"category","in":"query","required":false,"description":"Category name, matched exactly (case-sensitive). Unknown categories return an empty list.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Filter by commission type.","schema":{"type":"string","enum":["recurring","one-time","tiered","hybrid"]}},{"name":"verified","in":"query","required":false,"description":"true restricts results to verified entries; false or omission does not filter verification status.","schema":{"type":"boolean","default":false}},{"name":"include_description","in":"query","required":false,"description":"Include description text in keyword matching (descriptions are always returned).","schema":{"type":"boolean","default":false}},{"name":"sort","in":"query","required":false,"description":"Result order. relevance puts name matches first when q is present, then orders by OAS (programs not scored yet after, by commission).","schema":{"type":"string","enum":["relevance","az","za","commission_desc","newest"],"default":"relevance"}},{"name":"limit","in":"query","required":false,"description":"Maximum results, capped at 500. Zero or omission means all remaining results.","schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"default":0}},{"name":"offset","in":"query","required":false,"description":"Skip this many results before applying limit.","schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"default":0}}],"responses":{"200":{"description":"Matching active programs (possibly none).","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgramSearch"}}}},"400":{"description":"API-Version names a version this API does not serve.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/programs/{slug}":{"get":{"operationId":"getProgram","summary":"Get a program by slug","description":"Read a program, including paused entries and brands with no public program. Aliases resolve to the canonical slug in the 200 response. Unverified cookie, approval and payout terms are withheld. no_program and discontinued entries have neutral commission/payout placeholders, answer and alternatives rather than joinable terms.","parameters":[{"name":"slug","in":"path","required":true,"description":"Canonical program slug or a registered alias.","schema":{"type":"string"}},{"name":"API-Version","in":"header","required":false,"description":"Pin the API major version. Omitted means the current version, 1. Any other value returns 400 UNSUPPORTED_API_VERSION.","schema":{"type":"string","enum":["1"],"default":"1"}}],"responses":{"200":{"description":"Program details or a no-program answer.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Program"}}}},"400":{"description":"API-Version names a version this API does not serve.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No program or alias matches the slug.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/submissions":{"post":{"operationId":"submitProgram","summary":"Submit a missing program for verification","description":"Queue the brand's own affiliate program page for a maintainer to verify against the brand's published terms. Not instant: nothing is listed and no score exists until the terms are verified. Look the program up first (GET /api/programs?q= or /api/programs/{slug}). A domain already listed answers 200 with listingUrl; a domain already in the queue answers 200 with that submission (duplicate: true). The submitted URL is never fetched at submit time. The contact email is optional, never shown and never returned. Rate limited per address, per domain and site-wide; a 429 carries Retry-After.","parameters":[{"name":"API-Version","in":"header","required":false,"description":"Pin the API major version. Omitted means the current version, 1. Any other value returns 400 UNSUPPORTED_API_VERSION.","schema":{"type":"string","enum":["1"],"default":"1"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionRequest"}}}},"responses":{"200":{"description":"Already listed, or already in the queue.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"description":"Seconds until the window that refused the request ends.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests allowed in that window.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until that window ends.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionAccepted"}}}},"202":{"description":"Queued.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"description":"Seconds until the window that refused the request ends.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests allowed in that window.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until that window ends.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionAccepted"}}}},"400":{"description":"A field is invalid (SubmissionError, field names it), or API-Version is unsupported (Error).","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SubmissionError"},{"$ref":"#/components/schemas/Error"}]}}}},"403":{"description":"A Turnstile token was sent and did not pass.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"413":{"description":"The body is larger than 8 KB.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"415":{"description":"The body is not application/json.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"429":{"description":"Rate limited.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"description":"Seconds until the window that refused the request ends.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests allowed in that window.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until that window ends.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"503":{"description":"Submissions are not enabled on this deployment.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}}}}},"/api/submissions/{id}":{"get":{"operationId":"getSubmission","summary":"Read a submission's status","description":"Status of a submission by the id POST /api/submissions returned: queued, verifying, listed (with listingUrl, and reportUrl once scored) or rejected (with a one-sentence reason). Never returns the contact, the submitted URL or the note.","parameters":[{"name":"id","in":"path","required":true,"description":"Submission id (a UUID).","schema":{"type":"string","format":"uuid"}},{"name":"API-Version","in":"header","required":false,"description":"Pin the API major version. Omitted means the current version, 1. Any other value returns 400 UNSUPPORTED_API_VERSION.","schema":{"type":"string","enum":["1"],"default":"1"}}],"responses":{"200":{"description":"The submission's status.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"API-Version names a version this API does not serve.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No submission has this id.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"429":{"description":"Too many reads from this address; retry after a minute.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"description":"Seconds until the window that refused the request ends.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests allowed in that window.","schema":{"type":"integer","minimum":0}},"RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until that window ends.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}},"503":{"description":"Submissions are not enabled on this deployment.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionError"}}}}}}},"/api/categories":{"get":{"operationId":"listCategories","summary":"List categories with counts","description":"Return every registry category and its active program count. Paused, discontinued and no_program entries do not count.","parameters":[{"name":"API-Version","in":"header","required":false,"description":"Pin the API major version. Omitted means the current version, 1. Any other value returns 400 UNSUPPORTED_API_VERSION.","schema":{"type":"string","enum":["1"],"default":"1"}}],"responses":{"200":{"description":"Categories and total category count.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryList"}}}},"400":{"description":"API-Version names a version this API does not serve.","headers":{"API-Version":{"$ref":"#/components/headers/APIVersion"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"headers":{"APIVersion":{"description":"Major version of this API. Breaking changes ship only under a new value.","schema":{"type":"string","const":"1"}},"Deprecation":{"description":"RFC 9745. Sent only once the endpoint, or a parameter or field it serves, is deprecated: the deprecation date as a structured-field Date (e.g. @1767225600). Sent at least 90 days before Sunset. Nothing is deprecated today.","schema":{"type":"string","pattern":"^@-?[0-9]+$"}},"Sunset":{"description":"RFC 8594. Sent with Deprecation: the HTTP-date after which the deprecated endpoint, parameter or field stops working (e.g. Thu, 01 Apr 2027 00:00:00 GMT).","schema":{"type":"string"}}},"schemas":{"Commission":{"type":"object","properties":{"type":{"type":"string","enum":["recurring","one-time","tiered","hybrid","none"]},"rate":{"type":["string","number"]},"mode":{"type":"string","enum":["percentage","flat","tiered","hybrid","unknown"]},"value":{"type":["number","null"]},"currency":{"type":["string","null"]},"duration":{"type":["string","null"]},"conditions":{"type":["string","null"]}},"required":["type","rate","mode","value","currency"],"additionalProperties":false},"Program":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"logo":{"type":"string"},"category":{"type":"string"},"commission":{"$ref":"#/components/schemas/Commission"},"cookieDays":{"type":"integer","minimum":0},"payout":{"type":"object","properties":{"minimum":{"type":"number"},"currency":{"type":"string"},"frequency":{"type":"string"},"methods":{"type":"array","items":{"type":"string"}},"conditions":{"type":"string"}},"required":[],"additionalProperties":false},"description":{"type":"string"},"shortDescription":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"stars":{"type":"number"},"verified":{"type":"boolean"},"agentPrompt":{"type":"string"},"submittedBy":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"signupUrl":{"type":"string"},"approval":{"type":"string"},"approvalTime":{"type":["string","null"]},"restrictions":{"type":"array","items":{"type":"string"}},"commissionDuration":{"type":["string","null"]},"commissionConditions":{"type":["string","null"]},"attribution":{"type":"string"},"trackingMethod":{"type":"string"},"payoutMethods":{"type":"array","items":{"type":"string"}},"marketingMaterials":{"type":"boolean"},"apiAvailable":{"type":"boolean"},"dedicatedManager":{"type":"boolean"},"dashboardUrl":{"type":["string","null"]},"network":{"type":["string","null"]},"programAge":{"type":["string","null"]},"agentKeywords":{"type":"array","items":{"type":"string"}},"agentUseCases":{"type":"array","items":{"type":"string"}},"source":{"type":"string"},"lastVerifiedAt":{"type":["string","null"]},"aliases":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["active","paused","discontinued","no_program"]},"statusNote":{"type":["string","null"]},"claimedBy":{"type":["string","null"]},"alsoOn":{"type":["object","null"],"properties":{"affitor":{"type":"object","properties":{"url":{"type":"string"},"commission":{"$ref":"#/components/schemas/Commission"}},"required":["url"],"additionalProperties":false}},"additionalProperties":false},"kind":{"type":"string","enum":["affiliate","referral","creator-payout","revenue-share","cashback","partner-network"]},"statusCheckedAt":{"type":"string"},"answer":{"type":"string"},"oas":{"type":"object","properties":{"score":{"type":["number","null"]},"grade":{"type":["string","null"]},"status":{"type":"string","enum":["scored","stale","in_progress"]},"summary":{"type":"string"},"checkedAt":{"type":["string","null"]},"validUntil":{"type":["string","null"]},"version":{"type":"string"},"reportUrl":{"type":"string"}},"required":["score","grade","status","summary","checkedAt","validUntil","version","reportUrl"],"additionalProperties":false},"oasMachineChecks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["A1","P5","P6"]},"label":{"type":"string"},"met":{"type":"boolean"},"reading":{"type":"string"},"source":{"type":"string","enum":["http","pagespeed","dataforseo"]},"target":{"type":"string"},"measurement":{"oneOf":[{"type":"object","properties":{"status":{"type":"integer","const":200}},"required":["status"],"additionalProperties":false},{"type":"object","properties":{"data":{"type":"string","const":"field"},"notGood":{"type":"array","items":{"type":"string"}}},"required":["data","notGood"],"additionalProperties":false},{"type":"object","properties":{"data":{"type":"string","const":"lab"},"lcpMs":{"type":"number"},"cls":{"type":"number"},"tbtMs":{"type":"number"}},"required":["data","lcpMs","cls","tbtMs"],"additionalProperties":false},{"type":"object","properties":{"scope":{"type":"string","const":"worldwide"},"threshold":{"type":"integer"},"reached":{"type":"boolean"}},"required":["scope","threshold","reached"],"additionalProperties":false}]},"ruleset":{"type":"string"},"measuredAt":{"type":"string"},"validUntil":{"type":"string"}},"required":["id","label","met","reading","source","target","measurement","ruleset","measuredAt","validUntil"],"additionalProperties":false}},"alternatives":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"commission":{"type":"string"},"url":{"type":"string"}},"required":["slug","name","commission","url"],"additionalProperties":false}}},"required":["slug","name","url","logo","category","commission","payout","description","shortDescription","tags","stars","verified","agentPrompt","submittedBy","createdAt"],"additionalProperties":false},"ProgramSearch":{"type":"object","properties":{"programs":{"type":"array","items":{"$ref":"#/components/schemas/Program"}},"total":{"type":"integer","minimum":0},"filters":{"type":"object","properties":{"q":{"type":["string","null"]},"category":{"type":["string","null"]},"type":{"type":["string","null"]},"sort":{"type":"string"}},"required":["q","category","type","sort"],"additionalProperties":false}},"required":["programs","total","filters"],"additionalProperties":false},"CategoryList":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer","minimum":0}},"required":["name","count"],"additionalProperties":false}},"total":{"type":"integer","minimum":0}},"required":["categories","total"],"additionalProperties":false},"SubmissionRequest":{"type":"object","properties":{"programUrl":{"type":"string","maxLength":500,"description":"https:// link to the program page on the brand's own website."},"termsUrl":{"type":"string","maxLength":500,"description":"https:// link to the page that states the terms, when different."},"name":{"type":"string","maxLength":100},"contact":{"type":"string","maxLength":320,"description":"Optional email; never shown, never returned, cleared 30 days after the submission is decided."},"note":{"type":"string","maxLength":1000},"turnstileToken":{"type":"string","description":"Sent by the openaffiliate.dev form only; API callers leave it out."}},"required":["programUrl"],"additionalProperties":false},"SubmissionAccepted":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","verifying","listed"]},"statusUrl":{"type":"string"},"duplicate":{"type":"boolean"},"listingUrl":{"type":"string"},"reportUrl":{"type":"string"}},"required":["status"],"additionalProperties":false},"Submission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","verifying","listed","rejected"]},"reason":{"type":"string"},"listingUrl":{"type":"string"},"reportUrl":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","status","createdAt","updatedAt"],"additionalProperties":false},"SubmissionError":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"field":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"hint":{"type":"string"}},"required":["code","message","hint"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}