Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
openapi: 3.2.0
info:
title: EpicDirectories Payments API
description: API-first directory data platform.
version: '1.0'
contact: {}
servers:
- url: https://api.epicdirectories.com
description: Production
- url: http://localhost:3333
description: Local development
tags:
- name: Payments
paths:
/public/v1/directories/{directory}/offers:
get:
operationId: PaymentsController_offers
summary: What this directory sells (anonymous)
description: 'Unauthenticated, and safe to call from a browser — it exposes no credential, no Stripe id and no redirect URL.
Returns one entry per product: `{ kind, enabled, priceCents?, currency?, name? }`.
**Render a button if and only if `priceCents` is present.** An entry with `enabled: true` and no price carries `misconfigured: true` instead — the operator has opted in and the terms are broken, so checkout would answer 503. That is reported rather than advertised.
**404 when the directory sells nothing at all**, and deliberately the same 404 as an unknown directory: the checkout routes refuse to tell those two apart so that this API cannot be used to enumerate slugs, and an endpoint that answered 200 for every directory that exists would hand that distinction straight back. A consumer sees no difference — either way there is nothing to render.
Prices come from the same function the CHARGE comes from, so a quote here and the amount Stripe collects cannot drift.'
parameters:
- name: directory
required: true
in: path
schema:
type: string
responses:
'200':
description: The products this directory sells
'404':
description: Directory not found, or it sells nothing
tags:
- Payments
/public/v1/directories/{directory}/listings/{listingType}/{listingSlug}/checkout:
post:
operationId: PaymentsController_create
summary: Start checkout for a premium listing boost (anonymous)
description: 'Unauthenticated. Requires the directory to have opted in via `monetizationPolicy.boost.enabled = true`; otherwise 404 — a directory sells nothing by default.
Returns a Stripe Checkout URL to redirect the buyer to. **Send no body.** The price, currency and return URLs all come from the directory''s own configuration, and a request carrying an `amountCents` (or anything else) is rejected with 400 rather than ignored.
The boost is permanent — there is no renewal — and a listing can therefore only be boosted once: a listing that is already premium returns 409 rather than taking money for nothing.
**Nothing is granted by this call, and nothing is granted by the buyer reaching the success URL.** The boost is applied when Stripe confirms payment over its webhook. A consumer must not treat the success redirect as proof of payment; it is reachable by anyone who knows the URL.
Rate limited to **10 per hour per IP**.'
parameters:
- name: directory
required: true
in: path
schema:
type: string
- name: listingType
required: true
in: path
schema:
type: string
- name: listingSlug
required: true
in: path
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateCheckoutDto'
responses:
'200':
description: Checkout session created; redirect the buyer to `url`
'400':
description: A body field was sent — this endpoint accepts none
'404':
description: Directory or listing not found, or boosts not enabled
'409':
description: The listing is already a premium listing
'429':
description: Rate limit exceeded
'503':
description: Payments are not configured, or the directory's boost settings are invalid
tags:
- Payments
/public/v1/directories/{directory}/checkout/{kind}:
post:
operationId: PaymentsController_createContent
summary: Start checkout for a guest post or niche edit (anonymous)
description: 'Unauthenticated. `kind` is `guest_post` or `niche_edit`. Requires the directory to have opted in via `monetizationPolicy.guestPost.enabled = true` (or `nicheEdit`); otherwise 404 — a directory sells nothing by default, and enabling one product never enables another.
Returns a Stripe Checkout URL to redirect the buyer to. **Send no body.** The price, currency and return URLs all come from the directory''s own configuration, and a request carrying an `amountCents` (or anything else) is rejected with 400 rather than ignored.
**The buyer''s brief is collected ON THE STRIPE PAGE**, as up to three custom fields — the link destination, the anchor text, and either a topic (guest post) or which existing post to edit (niche edit). They come back inside the signed webhook, so a paid order always has a brief. The article copy itself does not fit a Stripe field and arrives by email.
Unlike the boost route there is **no duplicate guard**: these are repeatable, and someone may legitimately buy three guest posts.
**Nothing is created by this call, and nothing is created by the buyer reaching the success URL.** The order is created when Stripe confirms payment over its webhook. A consumer must not treat the success redirect as proof of payment; it is reachable by anyone who knows the URL.
Rate limited to **10 per hour per IP**.'
parameters:
- name: directory
required: true
in: path
schema:
type: string
- name: kind
required: true
in: path
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateCheckoutDto'
responses:
'200':
description: Checkout session created; redirect the buyer to `url`
'400':
description: A body field was sent, or `kind` was `listing_boost` — premium listings are bought through the listing checkout route
'404':
description: Unknown product, directory not found, or this product is not enabled
'429':
description: Rate limit exceeded
'503':
description: Payments are not configured, or the directory's settings for this product are invalid
tags:
- Payments
components:
schemas:
CreateCheckoutDto:
type: object
properties: {}
securitySchemes:
bearer:
scheme: bearer
bearerFormat: JWT
type: http
apiKey:
type: apiKey
in: header
name: x-api-key
x-provenance:
method: harvested
publisher: EpicDirectories
source: https://api.epicdirectories.com/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)