For developers and partners
Talkspresso API reference
Read and manage bookings, services and organizations with a scoped API key.
Authentication
Create a key in Settings > API keys. Keys start with tsp_. Choose the scopes it needs when you create it. A key cannot create or manage other keys.
Send the key in the Authorization header of every request. The API base address is https://api.talkspresso.com.
curl https://api.talkspresso.com/organization/my \
-H "Authorization: Bearer tsp_your_key_here"Keep the key on your server. Anyone who has it can do whatever its scopes allow. If it leaks, revoke it on the same page.
Scopes
A key can do only what its scopes allow. A route no scope covers is closed to every key. New keys start with read and you add the others one by one.
| Scope | What it allows |
|---|---|
| read | See your bookings, clients, services, products and earnings |
| bookings:write | Create, approve, decline, reschedule and cancel bookings; change your availability |
| catalog:write | Create and edit services, products, promo codes, intake questions, testimonials and your profile |
| clients:write | Edit client records, leads and notifications |
| messaging:send | Send messages and requests to your existing clients |
| org:write | Manage your organizations: branding, member updates, invitations |
Public endpoints
These two need no key. Use them to show an organization and its people on your own site. They are read only. Replace startupnash with the organization’s slug.
Get an organization
GET /organization/public/:slug
curl https://api.talkspresso.com/organization/public/startupnash{
"data": {
"id": "org_startupnash_2024",
"name": "StartupNash",
"slug": "startupnash",
"tagline": null,
"description": "A Slack community for founders and funders...",
"logo_url": "https://talkspresso.nyc3.digitaloceanspaces.com/uploads/org-logos/startupnash-logo.png",
"icon_url": "https://talkspresso.nyc3.digitaloceanspaces.com/uploads/org-logos/startupnash-icon.png",
"hero_image_url": "",
"hero_title": "Book Time with Nashville's Best Startup Mentors",
"hero_subtitle": "Get personalized 1-on-1 advice from founders, investors, and operators...",
"primary_color": "#05073a",
"secondary_color": "#ffca30",
"accent_color": "#26f7b2",
"member_term_singular": "Coach",
"member_term_plural": "Coaches",
"session_term": "Session",
"session_term_plural": "Sessions",
"locale": "en",
"website_url": "https://startupnash.com",
"social_links": {
"twitter": "https://twitter.com/startupnash",
"linkedin": "https://linkedin.com/company/startupnash",
"instagram": null
},
"total_members": 12,
"stripe_test_mode": true,
"show_free_label": false,
"payments_enabled": true,
"noindex": true,
"term_plural_gaps": [],
"is_password_protected": false
}
}| Field | What it is |
|---|---|
| id, name, slug | The organization’s id, display name and the slug used in its web address. |
| tagline, description | Short line and longer description, as the organization wrote them. |
| logo_url, icon_url, hero_image_url | Image addresses. hero_image_url is an empty string when none is set. |
| hero_title, hero_subtitle | Headline and sub-headline for the organization’s marketplace page. |
| primary_color, secondary_color, accent_color | Brand colors as hex values. |
| member_term_singular, member_term_plural | What the organization calls its people, for example Coach and Coaches. |
| session_term, session_term_plural | What the organization calls a booking, for example Session and Sessions. |
| locale | Language code of the page, for example en. |
| website_url, social_links | The organization’s own site and its twitter, linkedin and instagram links (null when not set). |
| total_members | Number of members. |
| stripe_test_mode, show_free_label, term_plural_gaps | Display and test-mode settings for the marketplace page. |
| payments_enabled | True when members can take paid bookings. |
| noindex | True when the marketplace page asks search engines not to list it. |
| is_password_protected | True when the organization’s page asks visitors for a password. The password itself is never returned. |
An unknown slug returns 404 with { "error": "Community not found" }.
List an organization’s members
GET /organization/public/:slug/members
Optional query parameters: featured=true returns only featured members, and limit caps how many come back. total is the count of members that match, before limit. The order of members is not guaranteed.
curl "https://api.talkspresso.com/organization/public/startupnash/members?limit=1"{
"data": {
"members": [
{
"id": "om_sn_jennifer",
"member_title": "Fundraising Advisor & Angel Investor",
"member_bio": null,
"is_featured": true,
"hide_price": false,
"total_sessions": 0,
"user": { "id": "sn_jennifer", "name": "Jennifer Chen" },
"profile": {
"profile_handle": "jennifer-chen",
"profile_photo": "/images/startupnash/jennifer.jpg",
"category": null,
"experience_summary": "VP of Engineering with 15+ years building high-scale systems...",
"action_headline": "",
"video": "https://talkspresso.nyc3.digitaloceanspaces.com/uploads/videos/startupnash/jennifer.mp4"
},
"starting_price": 200,
"pricing_type": "paid",
"services_count": 1
}
],
"total": 19
}
}| Field | What it is |
|---|---|
| id, member_title, member_bio | The membership id, the title shown under the person’s name, and an optional bio (null when not set). |
| is_featured | True when the organization highlights this person. |
| hide_price | True when the organization hides this person’s price on its page. |
| total_sessions | Number of sessions completed. |
| user.id, user.name | The person’s id and display name. |
| profile.profile_handle | Their Talkspresso page handle: talkspresso.com/{profile_handle}. |
| profile.profile_photo, profile.video | Photo and intro video addresses. video is null when none is set. |
| profile.category, profile.experience_summary, profile.action_headline | Category, short experience line and headline from their profile. |
| starting_price, pricing_type | The lowest service price in US dollars, and whether the person’s services are paid. |
| services_count | Number of services the person offers. |
An unknown slug returns 200 with an empty list and a total of 0.
Organization endpoints
These need a key. The key’s owner must also be an admin of the organization; a key owned by anyone else gets a 403 on these routes.
Read
Needs the read scope. Replace ORG_ID with the organization’s id, which GET /organization/my returns.
curl https://api.talkspresso.com/organization/my \
-H "Authorization: Bearer tsp_your_key_here"| Request and what comes back | Scope |
|---|---|
| GET /organization/myThe organizations you belong to, with your role in each. | read |
| GET /organization/:idThe full organization: branding, terms, locale, settings. | read |
| GET /organization/:id/membersdata.members and data.total. Query: status, featured, limit, offset. | read |
| GET /organization/:id/statstotalMembers, activeMembers, totalSessions, totalRevenue, pendingCommissions, paidCommissions. | read |
| GET /organization/:id/activitydata.rows (start_time, end_time, duration, timezone, consultant, client, service, lifecycle, money), total. | read |
| GET /organization/:id/activity/overviewneeds_you (awaiting_approval, recent_cancellations, consultants_without_a_rate) and coming_up. | read |
| GET /organization/:id/reporting/summarysessionCount and money totals in cents: grossCents, platformFeeCents, paypalFeeCents, netCents, consultantShareCents, orgShareCents. | read |
| GET /organization/:id/payoutsdata.payouts and data.total. | read |
Activity and reporting reads answer a key whose owner is not an admin of the organization with 404.
Manage
Needs the org:write scope.
curl -X PATCH https://api.talkspresso.com/organization/ORG_ID \
-H "Authorization: Bearer tsp_your_key_here" \
-H "Content-Type: application/json" \
-d '{"tagline": "Founders helping founders"}'curl -X POST https://api.talkspresso.com/organization/ORG_ID/invitations \
-H "Authorization: Bearer tsp_your_key_here" \
-H "Content-Type: application/json" \
-d '{"email": "coach@example.com", "name": "Alex Coach", "member_title": "Business coach"}'| Request and what comes back | Scope |
|---|---|
| PATCH or PUT /organization/:idThe updated organization. Only branding and wording fields are applied (see the list below). Other fields are ignored with a 200. | org:write |
| PATCH or PUT /organization/:id/members/:memberIdUpdates a membership, for example {"member_title": "..."}. :memberId is the membership id, not the user id. | org:write |
| DELETE /organization/:id/members/:memberId{"message": "Member removed successfully"} | org:write |
| POST /organization/:id/invitationsBody {"email", "name", "member_title"}. Returns the invitation. | org:write |
Fields an organization update applies:
name, slug, logo_url, icon_url, favicon_url, primary_color, secondary_color, accent_color, tagline, description, hero_image_url, hero_title, hero_subtitle, member_term_singular, member_term_plural, session_term, session_term_plural, locale (en or es-CL)
Members join an organization by invitation (POST /organization/:id/invitations), or Talkspresso creates their accounts on request. A key cannot create or import members directly.
Some things are never open to a key: deleting an organization, adding organization admins, impersonating a member, setting revenue shares, changing reporting or the contact email, and creating an organization.
Provider endpoints
A key acts as its owner. These routes work on the owner’s own account: their bookings, clients, services and earnings. Each route needs the scope shown.
read
| Method | Path | Scope |
|---|---|---|
| GET | /user/me | read |
| GET | /profile/me | read |
| GET | /appointments/me | read |
| GET | /appointments/pending | read |
| GET | /appointments/:id | read |
| POST | /appointments/slots | read |
| GET | /calendar/me | read |
| GET | /client/my | read |
| GET | /client/:id/appointments | read |
| GET | /client/:id/session-history | read |
| GET | /client/:id/activity | read |
| GET | /transaction/my | read |
| GET | /service/me | read |
| GET | /service/:id | read |
| GET | /service/:id/bookings | read |
| GET | /product/me | read |
| GET | /product/:id | read |
| GET | /product/purchases | read |
| GET | /product/analytics | read |
| GET | /promo-code | read |
| GET | /testimonial | read |
| GET | /recordings | read |
| GET | /messaging/conversations | read |
| GET | /messaging/conversations/:id/messages | read |
| GET | /payout/earnings | read |
| GET | /payout/history | read |
bookings:write
| Method | Path | Scope |
|---|---|---|
| POST | /appointments/invite | bookings:write |
| POST | /appointments/:id/approve | bookings:write |
| POST | /appointments/:id/decline | bookings:write |
| POST | /appointments/:id/cancel | bookings:write |
| POST | /appointments/:id/reschedule | bookings:write |
| POST | /appointments/:id/resend-invite | bookings:write |
| PUT | /calendar | bookings:write |
catalog:write
| Method | Path | Scope |
|---|---|---|
| PUT | /profile | catalog:write |
| POST | /service | catalog:write |
| PUT | /service/:id | catalog:write |
| DELETE | /service/:id | catalog:write |
| POST | /service/:id/duplicate | catalog:write |
| POST | /product | catalog:write |
| PUT | /product/:id | catalog:write |
| DELETE | /product/:id | catalog:write |
| POST | /promo-code | catalog:write |
| PUT | /promo-code/:id | catalog:write |
| DELETE | /promo-code/:id | catalog:write |
| POST | /testimonial | catalog:write |
messaging:send
| Method | Path | Scope |
|---|---|---|
| POST | /messaging/conversations/:id/messages | messaging:send |
| POST | /testimonial/request | messaging:send |
What comes back
These calls have been run against the API and return 200.
| Request and what comes back | Scope |
|---|---|
| GET /user/meThe user record. | read |
| GET /profile/meThe profile. | read |
| GET /service/medata.services (id, title, price, duration, status, slug, is_published, ...) and data.totalCount. | read |
| GET /appointments/medata.appointments, upcoming_sessions, completed_sessions, earned_this_month. | read |
| GET /client/mydata.clients and data.totalCount. | read |
| GET /transaction/mydata.transactions, totalCount, totalPages, page, limit. | read |
| GET /calendar/meAvailability by weekday, timezone, buffers, minimum notice. | read |
| GET /product/medata.products, totalCount, totalPages, page, limit. | read |
| POST /serviceThe new service. title is required. | catalog:write |
| PUT /service/:id{"data": {"message": "Service updated", "service": {...}}} | catalog:write |
| DELETE /service/:id{"data": {"message": "Service deleted", "deleted": true, ...}} | catalog:write |
The tables above are the most-used routes, not every route. A route that is not offered to keys returns 403 route_not_available_to_api_keys.
Errors
Errors use the normal HTTP status. These are the ones you will meet first.
| Status | Message or code, and what it means |
|---|---|
| 401 | Authentication token missingThe request has no Authorization header. |
| 401 | TOKEN EXPIRED OR INVALIDThe key is wrong, revoked or mistyped. |
| 403 | This API key is not allowed to do thisThe key is valid, but it does not hold the scope this route needs, or the route is not open to keys. The message says why. |
| 401 | Invalid or revoked API keyThe key was revoked. |
| 403 | You don’t have permission to update this organizationThe key has the scope, but its owner is not an admin of this organization. The wording varies by route. |
| 404 | org_not_foundAn activity or reporting read by a key whose owner is not an admin of the organization. |
| 401 | A plain-language messageA request the organization routes reject as invalid, such as an unsupported locale or a missing email, currently also arrives as 401 with the reason in the message. Read the message. |
| 404 | Community not foundThe organization slug does not exist (public organization endpoint). |
For “This API key is not allowed to do this”, the message includes a reason in brackets, for example missing_scope:bookings:write (add that scope to the key) or route_not_available_to_api_keys (no scope opens this route).
Rate limits
Responses include x-ratelimit-total, x-ratelimit-remaining and x-ratelimit-reset headers. Read them and slow down as remaining nears zero. In our tests x-ratelimit-total was 2000. Limits per route are not published yet.
Not available yet
- Single sign-on for your members
- Webhooks
- Creating an organization (we set it up for you)
- Your own domain on an organization’s marketplace page
Need one of these or want an organization set up? Email support@talkspresso.com.
Using an AI assistant instead of code? See Run Talkspresso from ChatGPT or Claude.