Developers

Lensdrop developer docs

Last updated August 23, 2026

Lensdrop is a photo delivery tool for photographers, not a developer platform. Its one public API is this read-only content API: every marketing page as markdown, an llms.txt index, and the discovery files agents expect. It needs no key, no account, and no registration. Uploads, payments, and gallery delivery have no third-party API; see what is not public.

Machine-readable version of this page: /developers.md. Full API description: /openapi.json.

Discovery files

PathTypeWhat it is
/llms.txttext/markdownAgent-readable index of Lensdrop's public content (llmstxt.org).
/llms-full.txttext/markdownEvery public page as one markdown document.
/openapi.jsonapplication/openapi+jsonOpenAPI 3.1 description of the content API, with operationIds, typed errors, and headers.
/.well-known/api-catalogapplication/linkset+jsonRFC 9727 API catalog pointing at the spec and the docs.
/auth.mdtext/markdownAuth.md: how (and whether) agents authenticate. Short answer: anonymous.
/developers.mdtext/markdownThis page, as markdown.
/sitemap.xmlapplication/xmlEvery indexable page.
/robots.txttext/plainCrawl rules. AI crawlers are allowed by name; galleries and the signed-in app are not crawlable.

Quickstart

Everything is a plain anonymous GET on https://lensdrop.app. Every markdown page is also reachable by requesting its HTML URL with Accept: text/markdown.

Read the index

curl https://lensdrop.app/llms.txt

Fetch a page as markdown by URL

curl https://lensdrop.app/pricing.md

Or by content negotiation on the HTML URL

curl -H "Accept: text/markdown" https://lensdrop.app/pricing

Get the OpenAPI description

curl https://lensdrop.app/openapi.json

See an error (typed, RFC 9457)

curl -i https://lensdrop.app/blog/no-such-post.md

Endpoints

Operation ids and parameter schemas (including the valid slugs) are in openapi.json, ready for function-calling tool definitions.

OperationoperationIdSummaryReturns
GET /llms.txtgetLlmsTxtIndex of Lensdrop's agent-readable contenttext/markdown
GET /llms-full.txtgetLlmsFullTxtThe full agent-readable corpus in one documenttext/markdown
GET /index.mdgetHomeMarkdownWhat Lensdrop is and how delivery workstext/markdown
GET /pricing.mdgetPricingMarkdownLensdrop pricing: tiers, add-ons, free tier, billingtext/markdown
GET /download.mdgetDownloadMarkdownLensdrop desktop uploadertext/markdown
GET /help.mdgetHelpMarkdownLensdrop help and FAQtext/markdown
GET /use-cases.mdgetUseCasesMarkdownLensdrop use cases, all niches in one documenttext/markdown
GET /blog.mdgetBlogIndexMarkdownLensdrop blog indextext/markdown
GET /developers.mdgetDeveloperDocsMarkdownLensdrop developer docstext/markdown
GET /use-cases/{slug}.mdgetUseCaseMarkdownOne use case as markdowntext/markdown
GET /blog/{slug}.mdgetBlogPostMarkdownOne blog post as markdowntext/markdown
GET /openapi.jsongetOpenApiSpecOpenAPI 3.1 description of this APIapplication/openapi+json
GET /.well-known/api-cataloggetApiCatalogRFC 9727 API catalogapplication/linkset+json
GET /auth.mdgetAuthMdHow agents authenticate (they don't)text/markdown

Errors

Every error is an RFC 9457 problem details object served as application/problem+json, with a real HTTP status: never a 200 wrapping an error, never an HTML page for an API path. Fields: type (documentation URL for the code), title, status, code (stable, machine-readable), detail, hint (what to do next), and optional instance (the request path). error is a legacy alias of detail.

{
  "type": "https://lensdrop.app/developers#not_found",
  "title": "Not found",
  "status": 404,
  "code": "not_found",
  "detail": "No markdown twin at /blog/no-such-post.md.",
  "hint": "Start from /llms.txt for the agent-readable site index, /openapi.json for the API description, or /sitemap.xml for every page.",
  "instance": "/blog/no-such-post.md",
  "error": "No markdown twin at /blog/no-such-post.md."
}
StatusCodeTitleWhat to do
400bad_requestBad requestCheck the request body and parameters against the documented schema.
400unsupported_versionUnsupported API versionSend a supported value in the API-Version header, or omit the header to use the current version.
401unauthorizedUnauthorizedThe credential is missing, malformed, or revoked. The public content API needs no credential; other surfaces are not open to third parties.
403forbiddenForbiddenThe credential is valid but does not cover this resource.
404not_foundNot foundStart from /llms.txt for the agent-readable site index, /openapi.json for the API description, or /sitemap.xml for every page.
405method_not_allowedMethod not allowedThe content API is read-only: use GET or HEAD.
406not_acceptableNot acceptableThis resource is served as text/markdown or application/json. Adjust the Accept header.
409conflictConflictThe resource is in a state that does not allow this change. Re-read it and retry if appropriate.
413payload_too_largePayload too largeReduce the request size; uploads go directly to storage in parts, never through this API.
429rate_limitedToo many requestsWait for the number of seconds in Retry-After, then retry. The RateLimit and RateLimit-Policy headers describe the quota.
500internal_errorInternal errorRetry with backoff. If it persists, contact support with the instance path.
502bad_gatewayUpstream errorA dependency failed. Retry with backoff.
503service_unavailableService unavailableRetry after a short delay; honor Retry-After when present.

Unknown paths anywhere on the site return a real 404. Browsers get the HTML page, /api/* paths and JSON accepts get a problem document, and everything else (curl, agents) gets a markdown body with links to the discovery files above.

Rate limits

Anonymous access is limited per client IP to 120 requests per 60 seconds (sliding window), described by the IETF RateLimit header fields on every response. Exceeding it returns 429 rate_limited with Retry-After. Read RateLimit to self-throttle instead of retrying blindly.

HeaderMeaningExample
API-VersionThe API version that produced the response. Currently 1.1
RateLimit-PolicyThe quota policy (IETF RateLimit header fields): 120 requests per 60 seconds per client, sliding window."content-api";q=120;w=60
RateLimitLive quota state: r is the requests remaining in the window, t the seconds until it resets. Present whenever the limiter ran."content-api";r=119;t=60
Retry-AfterOn a 429 only: seconds to wait before retrying.12
DeprecationOnly on responses from a deprecated API version (RFC 9745): the date the deprecation was announced.@1767225600
SunsetOnly on responses from a deprecated API version (RFC 8594): the date it stops being served.Wed, 01 Jul 2026 00:00:00 GMT

Versioning and deprecation

The content API is versioned by the API-Version header. Every response states the version that produced it (currently 1). Requests may pin a version with the same header; omit it to get the current version. A pinned version this deployment no longer serves answers 400 with code unsupported_version and the supported list.

URLs and response shapes within a version only change additively: new fields, new endpoints, new headers. Removing or renaming anything means a new version.

When a version is deprecated, responses from it carry Deprecation (RFC 9745) and Sunset (RFC 8594) headers and a Link with rel="deprecation" pointing at the notice on this page, for at least 6 months before the sunset date. Deprecations are also listed in llms.txt.

No version has been deprecated yet.

What is not public

  • Gallery uploads, downloads, and the client viewer: no third-party API. Bytes move between browsers, storage, and an image worker through signed URLs, never through an app server that an integration could call.
  • Billing: photographers pay Lensdrop through Dodo Payments, the merchant of record for both currencies (INR in India, USD elsewhere). There is no API to create purchases, and there are never client-to-photographer payments.
  • Connected devices: the desktop uploader and camera FTP use per-device credentials that the app issues and can revoke. They are not API keys for general use and are not documented here.

Crawling and AI use

robots.txt allows search engines and AI crawlers by name (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, and others) on the public pages and publishes Content Signals permitting search, AI input, and AI training. Galleries (/g/), the signed-in app, and /api are not crawlable.

Contact

Questions about agent access or this API: hello@lensdrop.app. Product questions belong in the help center.

Message us