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.

Operations 9

POST /api/billing/cancel Cancels at the end of the paid period. Does not refund #
POST /api/billing/checkout Starts a hosted checkout for a paid plan #
GET /api/billing/invoices Lists the invoices issued to the signed-in account #
POST /api/billing/plan Moves an existing subscription onto a different plan, at the next renewal or… #
GET /api/billing/plan-history Lists every tier the signed-in account has been on, newest first #
GET /api/billing/portal Links out to the provider's portal, where a card is changed #
POST /api/billing/resume Keeps a subscription that was going to stop, on its existing period #
POST /api/billing/seats Changes how many seats a subscription sold by the seat is billed for, settling… #
GET /api/billing/subscription Reads the signed-in account's subscription, if it has one #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/dropto-run:dropto-run-billing-api"
All apis
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.

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.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

dropto-run-billing-api-openapi.yml Raw ↑
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