FirstSales Tutorials API
Public, no-auth tutorial content feed.
Public, no-auth tutorial content feed.
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/firstsales-io:firstsales-io-tutorials-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: Firstsales Io Tutorials API
version: 1.0.0
contact:
name: FirstSales Support
email: firstsales@support.communicate.so
url: https://firstsales.io
license:
name: Terms of Service
url: https://firstsales.io/terms-of-service/
termsOfService: https://firstsales.io/terms-of-service/
x-apiVersioning:
strategy: url-path
current: v1
pattern: https://firstsales.io/api/v1/{operation}
policyUrl: https://firstsales.io/developers/#versioning
note: A breaking change ships under a new prefix (/api/v2/); v1 keeps its contract. The unprefixed /api/{operation} form is an unversioned alias of the current version and may change without notice - call the /api/v1/ form.
x-deprecationPolicy:
minimumNoticeDays: 180
signalling: 'A deprecated version''s responses carry Deprecation: true and a Sunset header with the retirement date (RFC 8594), plus a Link rel="deprecation" to the migration notes.'
announcement: https://firstsales.io/developers/#deprecation-policy
policyUrl: https://firstsales.io/developers/#deprecation-policy
currentlyDeprecated: []
description: 'Operations tagged Tutorials across 2 of this provider''s published API definitions: firstsales-io-openapi.json, openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://firstsales.io
description: Production
security: []
tags:
- name: Tutorials
description: Public, no-auth tutorial content feed.
paths:
/api/v1/public/tutorials:
get:
operationId: listTutorials
summary: List public tutorials
description: Returns published tutorial content (slug, title, summary, steps, pro tips, FAQs) as structured JSON. Omit pagination params to fetch the full edge-cached feed, or pass limit/cursor for deterministic cursor pagination over the same stable slug order. Served from the edge cache with a 1-hour revalidation window, so it carries no per-IP limiter and never answers 429.
tags:
- Tutorials
security: []
parameters:
- name: locale
in: query
required: false
description: BCP-47 locale to overlay translated title/summary/content onto the English canonical tutorial.
schema:
type: string
example: es
- name: limit
in: query
required: false
description: Maximum tutorials to return in this page (1-100). Omit to return the full feed.
schema:
type: integer
minimum: 1
maximum: 100
example: 20
- name: cursor
in: query
required: false
description: Opaque cursor returned by pageInfo.nextCursor from a previous page.
schema:
type: string
responses:
'200':
description: List of tutorials.
content:
application/json:
schema:
type: object
properties:
tutorials:
type: array
items:
$ref: '#/components/schemas/PublicTutorial'
pageInfo:
$ref: '#/components/schemas/CursorPageInfo'
required:
- tutorials
- pageInfo
'400':
description: Invalid request — bad input, missing field, or malformed value.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://firstsales.io
description: Production
/api/v1/public/tutorials/{slug}:
get:
operationId: getTutorialBySlug
summary: Get one tutorial by slug
description: Returns a single tutorial's full content (steps, pro tips, FAQs) by its slug. Call listTutorials first to discover valid slugs. Returns 404 (not this operation's 400/500 error shape but the same Error schema) if the slug is unknown. Served from the edge cache with a 1-hour revalidation window, so it carries no per-IP limiter and never answers 429.
tags:
- Tutorials
security: []
parameters:
- name: slug
in: path
required: true
description: Tutorial slug, e.g. `cold-email-deliverability`.
schema:
type: string
- name: locale
in: query
required: false
description: BCP-47 locale to overlay translated content onto the English canonical tutorial.
schema:
type: string
example: es
responses:
'200':
description: The tutorial.
content:
application/json:
schema:
type: object
properties:
tutorial:
$ref: '#/components/schemas/PublicTutorial'
required:
- tutorial
'400':
description: Invalid request — bad input, missing field, or malformed value.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No tutorial exists for this slug.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
headers:
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
type: integer
RateLimit-Remaining:
description: Requests still available in the current window.
schema:
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimit-Policy:
description: Policy in the form "<limit>;w=<window seconds>".
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://firstsales.io
description: Production
components:
schemas:
Error:
type: object
description: Shared error envelope used by public endpoints and the rate-limit wrapper. Mail-tester handler errors use MailTesterError.
properties:
error:
type: string
description: Machine-readable error code, e.g. `invalid_input`.
message:
type: string
description: Human-readable explanation.
hint:
type: string
description: How to fix the request.
required:
- error
- message
- hint
CursorPageInfo:
type: object
properties:
nextCursor:
type:
- string
- 'null'
prevCursor:
type:
- string
- 'null'
hasMore:
type: boolean
total:
type: number
required:
- nextCursor
- prevCursor
- hasMore
- total
PublicTutorial:
type: object
properties:
slug:
type: string
title:
type: string
summary:
type: string
category:
type: string
industry:
type: string
difficulty:
type: string
enum:
- beginner
- intermediate
- advanced
estMinutes:
type: number
steps:
type: array
items:
type: object
proTips:
type: array
items:
type: object
faqs:
type: array
items:
type: object
required:
- slug
- title
- summary
- category
- difficulty
- estMinutes
- steps
- proTips
- faqs
x-refined-from:
- firstsales-io-openapi.json
- openapi.json
x-apiVersioning:
strategy: url-path
current: v1
pattern: https://firstsales.io/api/v1/{operation}
policyUrl: https://firstsales.io/developers/#versioning
note: A breaking change ships under a new prefix (/api/v2/); v1 keeps its contract. The unprefixed /api/{operation} form is an unversioned alias of the current version and may change without notice - call the /api/v1/ form.
x-deprecationPolicy:
minimumNoticeDays: 180
signalling: 'A deprecated version''s responses carry Deprecation: true and a Sunset header with the retirement date (RFC 8594), plus a Link rel="deprecation" to the migration notes.'
announcement: https://firstsales.io/developers/#deprecation-policy
policyUrl: https://firstsales.io/developers/#deprecation-policy
currentlyDeprecated: []