Dropto Plans API

The tiers and every ceiling they carry, read from the same table the server enforces against. The pricing page and the dashboard both read this, which is what stops a published limit and an enforced one from drifting apart.

Operations 2

GET /api/plans Lists the quota tiers the API enforces #
GET /api/plans/mine Lists the quota tiers this account may buy, including any agreed with it #

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-plans-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-plans-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Drop2Run.Api | v1 Plans API
  version: 1.0.0
  description: The tiers and every ceiling they carry, read from the same table the server enforces against. The pricing page and the dashboard both read this, which is what stops a published limit and an enforced one from drifting apart.
servers:
- description: Production
  url: https://dropto.run
tags:
- description: The tiers and every ceiling they carry, read from the same table the server enforces against. The pricing page and the dashboard both read this, which is what stops a published limit and an enforced one from drifting apart.
  name: Plans
paths:
  /api/plans:
    get:
      operationId: GetPlans
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlansResponse'
          description: OK
      summary: Lists the quota tiers the API enforces
      tags:
      - Plans
  /api/plans/mine:
    get:
      operationId: GetMyPlans
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlansResponse'
          description: OK
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Forbidden
      security:
      - session: []
      - accessToken: []
      summary: Lists the quota tiers this account may buy, including any agreed with it
      tags:
      - Plans
components:
  schemas:
    PlansResponse:
      description: Response of `GET /plans`.
      properties:
        anonymousPlanId:
          description: Tier applied to a site created without signing in.
          type: string
        contentDomain:
          description: 'Apex domain a site''s subdomain sits under, for example `dropto.live`. Served here rather than

            hardcoded in the frontend for the same reason every number above is: it is server configuration, and a

            client that guessed it would show the wrong suffix the moment the domain changed.'
          type: string
        plans:
          description: Every tier, smallest first.
          items:
            $ref: '#/components/schemas/PlanResponse'
          type: array
        signedInPlanId:
          description: Tier applied once the visitor has an account.
          type: string
      required:
      - plans
      - anonymousPlanId
      - signedInPlanId
      - contentDomain
      type: object
    PlanResponse:
      description: One quota tier. Field for field the `plans` row, so no mapping table is needed anywhere.
      properties:
        allowAnalyticsExport:
          description: 'Whether the dashboard offers to save this tier''s traffic figures as files.


            Another statement about what the tier is sold with rather than a lock: the files are assembled in

            the browser from the traffic response the page already holds, so a reader who can see the page can

            read the same numbers off it — see bool Plan.AllowAnalyticsExport.'
          type: boolean
        allowBrowserEdit:
          description: 'Whether the dashboard lets an owner edit a file of their site in the browser.


            A gate rather than packaging, like the flag above: the endpoint the editor reads a file through is

            refused outright for a tier without it.'
          type: boolean
        allowFeedback:
          description: 'Whether a site on this tier can take comments on its pages (docs/IMPLEMENTATION-PLAN.md §16.7).


            Served so the pricing page and the marketing pages say which tiers include comments from the table,

            never from a sentence: the tiers that carry it are set in the admin console and change without a release.'
          type: boolean
        allowInvitedViewers:
          description: 'Whether a site on this tier may be shared with named people, each signing in with their own account.

            A capability beside AllowPasswordProtection — the two are the paid answers to "who

            can see this site" — and served for the same reason: the pricing page lists it beside the password.'
          type: boolean
        allowPasswordProtection:
          description: 'Whether a site on this tier may be put behind a password. The first capability on this record rather

            than a quantity, so it reads as a boolean instead of a limit of zero: the tier either offers the

            feature or does not, and "0 passwords" would describe a countable resource nobody has any of.


            Served here for the same reason every number above is — the pricing page and the site settings form

            both have to know, and a client that hardcoded which tiers had it would be wrong the first time an

            operator flipped the column.'
          type: boolean
        allowQrCode:
          description: 'Whether the dashboard offers a QR code for the addresses of sites on this tier.


            Served rather than decided in the browser for the same reason the flag above is, and for one more:

            this is the only thing that decides the feature at all. The code is drawn from an address that is

            already public, so the tier''s answer is a statement about what the tier is sold with, not a lock —

            see bool Plan.AllowQrCode.'
          type: boolean
        allowScheduledExpiry:
          description: 'Whether an owner on this tier may schedule when one of their sites comes down.


            Unlike the two flags above, this one is a real gate rather than a statement about packaging: the

            server refuses to set a date for a tier without it. Served all the same, so the pricing page can

            list it and the dashboard can explain the absence rather than failing on submit.'
          type: boolean
        allowTrafficBreakdown:
          description: 'Whether this tier''s traffic page lists top pages, referrers, countries and broken links, and filters

            by them. Served so the pricing page and the locked panels can name the tier that includes them.'
          type: boolean
        allowTrafficDetail:
          description: 'Whether this tier''s traffic page splits people from bots and AI, and shows devices, browsers,

            campaigns and edge speed.'
          type: boolean
        analyticsDays:
          description: 'How many days of a site''s own traffic this tier lets its owner see, or zero when it includes none.


            A count where bool PlanResponse.AllowPasswordProtection is a flag, because there is something to meter

            here: the difference between tiers is how far back the history reaches, and a boolean would need a

            second field to say that. Zero reads as "not on this tier" rather than as a quantity nobody has,

            which is why the pricing page renders it as words rather than as the number.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        badgeText:
          description: Short label shown against the tier, or null for none. See string? Plan.BadgeText.
          type:
          - 'null'
          - string
        currency:
          description: ISO 4217 code the two price fields are counted in.
          type: string
        displayOrder:
          description: Where the tier sits on the pricing page, lowest first.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        id:
          description: Plan id, as stored.
          type: string
        isExclusive:
          description: 'Whether this tier is not on the pricing page, and reaches the caller only because it was agreed with

            them.


            Always false on the anonymous route, which returns the listed tiers and therefore has nothing to say

            here. It exists so the dashboard can label the card: a reader meeting a price nobody else is offered,

            beside prices everybody is, would otherwise have no way to tell which is which — and would reasonably

            wonder why they cannot find it on the pricing page.


            Not the same question as bool PlanResponse.IsPurchasable. A tier can be agreed before its prices are set,

            which is exclusive and not yet buyable, and the card has to say both.'
          type: boolean
        isPurchasable:
          description: 'Whether the tier can be bought right now. Separate from being listed: a tier that is listed and not

            purchasable shows its price and its limits with no button, which is how a tier is announced before

            there is a checkout behind it. See bool Plan.IsPurchasable.'
          type: boolean
        isTeam:
          description: 'Whether the two prices are the cost of one seat rather than of one period.


            Served publicly because the pricing page cannot render the tier without it: fifteen dollars a seat

            and fifteen dollars a period are the same number in the same field and three times apart in what a

            customer pays. A page that showed the column would put this tier beside the one above it at an

            identical price.'
          type: boolean
        lifetimeDays:
          description: Days before the site is deleted, or null when it is kept for good.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxAccountBytes:
          description: 'Maximum bytes the account may hold across every site and every kept version, or null when the tier

            has no total. Null on the anonymous tier, which has no owner to total by. See

            long? Plan.MaxAccountBytes.'
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxAccountWriteOpsPerMonth:
          description: 'New or changed files the account may publish in a calendar month, or null when the tier is not

            bounded by month. The one limit on this page that is a cost rather than a capacity: republishing a

            file that has not changed spends nothing against it.'
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxCustomDomains:
          description: 'Maximum hostnames of the customer''s own that one account may be served on, counted across every site

            it owns. Zero means the tier does not include the feature, which is what both free tiers are seeded

            with — so the pricing page reads this as a capability rather than as a quantity. Never null, unlike

            the quotas above it: there is no unlimited version of a resource billed monthly per unit. Distinct

            from int? PlanResponse.MaxCustomSubdomains, which counts names on our own content domain. See

            int Plan.MaxCustomDomains.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxCustomSubdomains:
          description: 'Maximum sites one owner may have picked their own subdomain for, or null when the tier does not limit

            that at all. See int? Plan.MaxCustomSubdomains.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxFileBytes:
          description: Maximum size of a single file, in bytes.
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxFiles:
          description: Maximum files in one deploy.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxFormSubmissionsPerMonth:
          description: 'Maximum form submissions one account may take in a calendar month, across every site it owns. Zero

            means the tier does not include the feature, and every tier is seeded zero — the figure worth selling

            is not known yet, so it ships off and an operator raises it per row once the counter has something to

            read. The pricing page therefore renders this as a capability until somebody sets a number. See

            int Plan.MaxFormSubmissionsPerMonth.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxFunctionInvocationsPerMonth:
          description: 'Function calls one account''s sites may make together in a calendar month, before seats. Zero means the tier

            does not include functions. See int Plan.MaxFunctionInvocationsPerMonth.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxFunctionSites:
          description: 'Sites of one account that may run functions at once (docs/briefs/FUNCTIONS-BRIEF.md D18). Zero, with

            MaxFunctionInvocationsPerMonth, means the tier does not include functions — every tier sold

            today, until an operator sets a figure on the row. See int Plan.MaxFunctionSites.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxProxyRequestsPerMonth:
          description: 'Requests one account''s sites may proxy to their owners'' upstreams in a calendar month. Zero means the tier

            does not include the proxy. See int Plan.MaxProxyRequestsPerMonth.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxSeats:
          description: Most seats it can be held with, or null for no ceiling.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxSiteBytes:
          description: 'Maximum total size of one deploy of one site, in bytes, or null when the tier does not bound a single

            publish and lets the account total do it instead. Not a storage limit either way: it is weighed

            against a single publish, and every kept version is stored whole. MaxAccountBytes

            is the storage one.'
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        maxSiteComments:
          description: 'The most comments one site on this tier may hold, deleted ones not counted. Only meaningful where

            AllowFeedback is on; served on every tier like the other ceilings.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxSiteViewers:
          description: 'How many people one invite-only site may list, its owner included. Read only where

            AllowInvitedViewers is on; a figure on a tier without the feature describes nothing.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        maxSites:
          description: 'Maximum sites one owner may have, or null when the tier has no owner to count by — the anonymous tier,

            whose sites belong to nobody.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        minSeats:
          description: Fewest seats the tier is sold with, which is what turns a seat price into an entry price.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        name:
          description: 'What the tier is called on screen, falling back to the id when a row has never been named. Served

            rather than written into the pricing page so that a tier added to the table appears with its own name

            instead of an id, which is what makes a new tier a database insert rather than a release.'
          type: string
        parentPlanId:
          description: 'The tier this one is built on, or null when it stands alone.


            Every quota above is already the effective one — inheritance is materialised on the row, so nothing

            reading this response has to resolve anything. This field is here for what the pricing page says

            rather than for what it computes: a tier built on another is listed as everything that one includes

            plus what it adds, and the rows that repeat the parent''s figures are left off the card. Without the

            link the page would have to guess that relationship from the numbers, and two tiers that happen to

            share a figure are not the same claim as one built on the other.


            Null on the card when the parent is not itself public: there is no listed tier to name, so the card

            falls back to listing every row.'
          type:
          - 'null'
          - string
        perSeatAccountBytes:
          description: 'Storage each seat past the minimum adds, or null when storage does not scale with seats.


            The per-seat figures are served for one reason, and it is not decoration. This endpoint is

            public, so it has no account and therefore no seat count — it can only state the tier''s base. The

            dashboard states the effective figure for the account reading it. Without the delta beside the base,

            the two pages say different numbers for the same plan and the promise that the pricing page shows

            what the service enforces stops being true.'
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        perSeatMaxCustomDomains:
          description: 'Hostnames of the customer''s own each seat past the minimum adds. Zero says a seat buys none, which

            is where every tier starts and what the free tiers stay at.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        perSeatMaxFormSubmissionsPerMonth:
          description: 'Form submissions a month each seat past the minimum adds to the account''s allowance. Zero says a

            seat buys none, which is every tier but Team.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        perSeatMaxFunctionInvocationsPerMonth:
          description: Function calls a month each seat past the minimum adds. Zero says a seat buys none.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        perSeatMaxProxyRequestsPerMonth:
          description: Proxied requests a month each seat past the minimum adds. Zero says a seat buys none.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        perSeatMaxSites:
          description: Sites each seat past the minimum adds, or null when they do not scale.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        perSeatWriteOpsPerDay:
          description: Daily budget each seat adds, or null when it does not scale.
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        perSeatWriteOpsPerMonth:
          description: Monthly budget each seat adds, or null when it does not scale.
          format: int64
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        priceCentsMonth:
          description: 'Price of one month in the smallest unit of Currency, or null when the tier is not

            sold by the month. Null rather than zero on the free tiers: they are not priced at zero, they are not

            on sale.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        priceCentsYear:
          description: Price of one year, or null when the tier is not sold by the year.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        prioritySupport:
          description: 'Whether support requests from accounts on this tier are answered ahead of the queue.


            Served because the pricing page lists it, and for no other reason: nothing in the API branches on

            it. It is the one field here that no endpoint enforces, because what it describes is a promise kept

            by whoever answers the mail — see bool Plan.PrioritySupport.'
          type: boolean
        retainedDeploys:
          description: How many recent deploys stay available.
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - integer
          - string
        showsBadge:
          description: 'Whether sites on this tier carry the Drop2Run badge in their served HTML.


            The one field on this record that describes something the platform does *to* a site rather than

            something the site is allowed to do, which is why it reads as "shows" rather than "allows". The

            pricing page states it as a row like any other limit, because it is a difference between the tiers a

            reader has to know before they upload rather than after.'
          type: boolean
        sitesPerIpPerDay:
          description: 'Maximum new sites one network may create per day, or null when the tier is not counted by address.

            Abuse protection rather than a product limit, so nothing is expected to display it.'
          format: int32
          pattern: ^-?(?:0|[1-9]\d*)$
          type:
          - 'null'
          - integer
          - string
        tagline:
          description: One line under the name, or null to show none. See string? Plan.Tagline.
          type:
          - 'null'
          - string
      required:
      - id
      - maxSites
      - maxSiteBytes
      - maxAccountBytes
      - maxAccountWriteOpsPerMonth
      - maxFiles
      - maxFileBytes
      - retainedDeploys
      - lifetimeDays
      - sitesPerIpPerDay
      - maxCustomSubdomains
      - maxCustomDomains
      - maxFormSubmissionsPerMonth
      - maxProxyRequestsPerMonth
      - allowPasswordProtection
      - allowInvitedViewers
      - maxSiteViewers
      - allowQrCode
      - allowAnalyticsExport
      - allowScheduledExpiry
      - allowBrowserEdit
      - allowFeedback
      - maxSiteComments
      - showsBadge
      - prioritySupport
      - analyticsDays
      - allowTrafficBreakdown
      - allowTrafficDetail
      - name
      - tagline
      - badgeText
      - priceCentsMonth
      - priceCentsYear
      - currency
      - isPurchasable
      - displayOrder
      - parentPlanId
      - isTeam
      - minSeats
      - maxSeats
      - perSeatAccountBytes
      - perSeatMaxSites
      - perSeatWriteOpsPerMonth
      - perSeatWriteOpsPerDay
      - perSeatMaxCustomDomains
      - perSeatMaxFormSubmissionsPerMonth
      - perSeatMaxProxyRequestsPerMonth
      - isExclusive
      - maxFunctionSites
      - maxFunctionInvocationsPerMonth
      - perSeatMaxFunctionInvocationsPerMonth
      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
  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