Dropto Billing API
Subscriptions, seats and invoices, through the payment provider that is the merchant of record. Publishing is free with or without an account; what is bought here is room, a custom domain and a page with no badge.
Subscriptions, seats and invoices, through the payment provider that is the merchant of record. Publishing is free with or without an account; what is bought here is room, a custom domain and a page with no badge.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/dropto-run:dropto-run-billing-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a 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.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Drop2Run.Api | v1 Billing API
version: 1.0.0
description: Subscriptions, seats and invoices, through the payment provider that is the merchant of record. Publishing is free with or without an account; what is bought here is room, a custom domain and a page with no badge.
servers:
- description: Production
url: https://dropto.run
tags:
- description: Subscriptions, seats and invoices, through the payment provider that is the merchant of record. Publishing is free with or without an account; what is bought here is room, a custom domain and a page with no badge.
name: Billing
paths:
/api/billing/cancel:
post:
operationId: CancelSubscription
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/BillingActionResponse'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
'409':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Conflict
security:
- session: []
- accessToken: []
summary: Cancels at the end of the paid period. Does not refund
tags:
- Billing
/api/billing/checkout:
post:
operationId: StartCheckout
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CheckoutRequestBody'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CheckoutResponse'
description: OK
'400':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Bad Request
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
'409':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Conflict
security:
- session: []
- accessToken: []
summary: Starts a hosted checkout for a paid plan
tags:
- Billing
/api/billing/invoices:
get:
operationId: GetInvoices
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/InvoicesResponse'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
security:
- session: []
- accessToken: []
summary: Lists the invoices issued to the signed-in account
tags:
- Billing
/api/billing/plan:
post:
operationId: ChangePlan
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ChangePlanRequestBody'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SubscriptionRow'
description: OK
'400':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Bad Request
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
'409':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Conflict
security:
- session: []
- accessToken: []
summary: Moves an existing subscription onto a different plan, at the next renewal or…
tags:
- Billing
/api/billing/plan-history:
get:
operationId: GetPlanHistory
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlanHistoryResponse'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
security:
- session: []
- accessToken: []
summary: Lists every tier the signed-in account has been on, newest first
tags:
- Billing
/api/billing/portal:
get:
operationId: GetBillingPortal
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PortalResponse'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
security:
- session: []
- accessToken: []
summary: Links out to the provider's portal, where a card is changed
tags:
- Billing
/api/billing/resume:
post:
operationId: ResumeSubscription
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SubscriptionRow'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
'409':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Conflict
security:
- session: []
- accessToken: []
summary: Keeps a subscription that was going to stop, on its existing period
tags:
- Billing
/api/billing/seats:
post:
operationId: ChangeSeats
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ChangeSeatsRequestBody'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SubscriptionRow'
description: OK
'400':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Bad Request
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
'404':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Not Found
'409':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Conflict
security:
- session: []
- accessToken: []
summary: Changes how many seats a subscription sold by the seat is billed for, settling…
tags:
- Billing
/api/billing/subscription:
get:
operationId: GetSubscription
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SubscriptionResponse'
description: OK
'403':
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
description: Forbidden
security:
- session: []
- accessToken: []
summary: Reads the signed-in account's subscription, if it has one
tags:
- Billing
components:
schemas:
BillingActionResponse:
description: Response of the billing actions that only ask the provider for something.
properties:
accepted:
description: Always true; the provider took the request.
type: boolean
required:
- accepted
type: object
SubscriptionRow:
description: One subscription, as the billing page renders it.
properties:
cancelAtPeriodEnd:
description: Whether it stops at the end of the current period.
type: boolean
currentPeriodEnd:
description: When the paid period ends; null while paused.
format: date-time
type:
- 'null'
- string
graceUntil:
description: When the grace window on a failed payment runs out, or null.
format: date-time
type:
- 'null'
- string
interval:
description: The billing interval.
type: string
pausedAt:
description: When it was paused, or null.
format: date-time
type:
- 'null'
- string
pendingInterval:
description: The interval it switches to at the next renewal, or null.
type:
- 'null'
- string
pendingPlanId:
description: The plan it switches to at the next renewal, or null.
type:
- 'null'
- string
planId:
description: The plan currently paid for.
type: string
seats:
description: How many seats are being paid for; one on every tier not sold by the seat.
format: int32
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
status:
description: One of the SubscriptionStatus names.
type: string
required:
- planId
- pendingPlanId
- status
- interval
- pendingInterval
- currentPeriodEnd
- cancelAtPeriodEnd
- graceUntil
- pausedAt
- seats
type: object
InvoiceRow:
description: One invoice, as the invoices page renders it.
properties:
amountCents:
description: Amount in the smallest unit of Currency.
format: int64
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
amountRefundedCents:
description: 'How much of it has been given back. Shown beside the charge rather than instead of it, so a partial
reversal reads as what it is — a status alone cannot say how much of the money came back.'
format: int64
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
currency:
description: ISO 4217 code.
type: string
hostedUrl:
description: Link to the provider's own copy, or null.
type:
- 'null'
- string
id:
description: Our own id for the invoice.
type: string
issuedAt:
description: When the provider issued it.
format: date-time
type: string
periodEnd:
description: End of the period covered, or null.
format: date-time
type:
- 'null'
- string
periodStart:
description: Start of the period covered, or null.
format: date-time
type:
- 'null'
- string
status:
description: One of the InvoiceStatus names.
type: string
required:
- id
- amountCents
- amountRefundedCents
- currency
- status
- periodStart
- periodEnd
- issuedAt
- hostedUrl
type: object
ChangePlanRequestBody:
description: Request body of `POST /api/billing/plan`.
properties:
interval:
description: Billing interval, `month` or `year`.
maxLength: 8
type: string
planId:
description: Id of the plan to move onto.
maxLength: 32
type: string
timing:
description: '`now`, or absent, which means the same thing: the change is applied immediately and the
difference is settled against the unused remainder of the current period. Kept in the contract only
so that `period_end` — which this route offered until the provider was found to have no way of
deferring anything — can be refused by name instead of being read as `now` and charging a
customer who was told nothing would be charged.'
maxLength: 16
type:
- 'null'
- string
required:
- planId
- interval
type: object
ProblemDetails:
properties:
detail:
type:
- 'null'
- string
instance:
type:
- 'null'
- string
status:
format: int32
pattern: ^-?(?:0|[1-9]\d*)$
type:
- 'null'
- integer
- string
title:
type:
- 'null'
- string
type:
type:
- 'null'
- string
type: object
PlanChangeRow:
description: One movement between tiers, as a page renders it.
properties:
fromInterval:
description: The billing term before, or null when there was none.
type:
- 'null'
- string
fromPlanId:
description: The tier before.
type: string
fromSeats:
description: Seats paid for before; one on every tier not sold by the seat.
format: int32
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
occurredAt:
description: When it happened.
format: date-time
type: string
reason:
description: 'Why it moved: one of PlanChangeReason.'
type: string
toInterval:
description: The billing term after, or null when there is none.
type:
- 'null'
- string
toPlanId:
description: The tier after.
type: string
toSeats:
description: Seats paid for afterwards.
format: int32
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
required:
- fromPlanId
- toPlanId
- fromInterval
- toInterval
- reason
- occurredAt
- fromSeats
- toSeats
type: object
CheckoutResponse:
description: Response of `POST /api/billing/checkout`.
properties:
checkoutUrl:
description: The provider-hosted page to send the buyer to.
type: string
required:
- checkoutUrl
type: object
PortalResponse:
description: Response of `GET /api/billing/portal`.
properties:
portalUrl:
description: Where to send the customer to manage their card and receipts.
type: string
required:
- portalUrl
type: object
InvoicesResponse:
description: Response of `GET /api/billing/invoices`.
properties:
invoices:
description: The account's invoices, newest first.
items:
$ref: '#/components/schemas/InvoiceRow'
type: array
required:
- invoices
type: object
ChangeSeatsRequestBody:
description: Request body of `POST /api/billing/seats`.
properties:
seats:
description: 'How many seats to be billed for from now on — the total, not a difference. A delta would make the
request depend on what the client last read, so two owners pressing "add a seat" at once would buy
two seats each.'
format: int32
pattern: ^-?(?:0|[1-9]\d*)$
type:
- integer
- string
required:
- seats
type: object
SubscriptionResponse:
description: Response of `GET /api/billing/subscription`.
properties:
pendingCheckout:
oneOf:
- type: 'null'
- $ref: '#/components/schemas/PendingCheckoutRow'
description: A checkout still being confirmed, or null when none is.
__uniqueRefKey: '#/components/schemas/PendingCheckoutRow__20'
subscription:
oneOf:
- type: 'null'
- $ref: '#/components/schemas/SubscriptionRow'
description: The current subscription, or null when there is none.
__uniqueRefKey: '#/components/schemas/SubscriptionRow__21'
required:
- subscription
- pendingCheckout
type: object
PlanHistoryResponse:
description: Response of `GET /api/billing/plan-history`.
properties:
changes:
description: The account's tier changes, newest first.
items:
$ref: '#/components/schemas/PlanChangeRow'
type: array
required:
- changes
type: object
PendingCheckoutRow:
description: A checkout still being confirmed, as the billing page renders it.
properties:
createdAt:
description: When the checkout began.
format: date-time
type: string
interval:
description: The billing interval chosen.
type: string
planId:
description: The plan the checkout is for.
type: string
status:
description: '`open` or `completed`.'
type: string
required:
- planId
- interval
- status
- createdAt
type: object
CheckoutRequestBody:
description: Request body of `POST /api/billing/checkout`.
properties:
interval:
description: Billing interval, `month` or `year`.
maxLength: 8
type: string
planId:
description: Id of the plan to buy.
maxLength: 32
type: string
required:
- planId
- interval
type: object
securitySchemes:
accessToken:
description: 'A personal access token, created at /account/tokens. Sent as `Authorization: Bearer d2r_...`. A rejected token answers 401 with `invalid_token`, which is deliberately distinct from the 403 a valid credential gets for something it may not do.'
scheme: bearer
type: http
claimToken:
description: Returned once when an anonymous site is created, and the only credential that site has until somebody signs in and claims it.
in: header
name: X-Claim-Token
type: apiKey
session:
description: The browser session, set by signing in with Google. HttpOnly, so a script cannot read it and a client outside a browser cannot send it.
in: cookie
name: d2r_session
type: apiKey