openapi: 3.1.0
info:
title: Sendoso Core API
version: '3'
summary: Automate physical gift, direct mail and eGift sending, and read campaigns, users and teams.
description: >-
The Sendoso Core API (v3) lets you programmatically trigger sends, embed sending into your
own forms, and read the campaigns ("touches"), users and team groups behind them. Sendoso
describes the API as "organized around REST principles ... predictable, resource-oriented
URLs ... HTTP response codes to indicate API errors", supporting GET and POST with JSON
request and response bodies.
Sendoso does not publish an OpenAPI document. This description was generated by API
Evangelist from Sendoso's own published reference pages at https://developer.sendoso.com —
every path, method, parameter and response field below is traceable to the page named in
that operation's `externalDocs`.
contact:
name: Sendoso Developer Support
email: developers@sendoso.com
url: https://developer.sendoso.com/
x-generated-from: documentation
x-generated-by: API Evangelist enrichment pipeline (local-v1)
x-generated-on: '2026-08-13'
x-source-docs: https://developer.sendoso.com/llms.txt
servers:
- url: https://app.sendoso.com
description: Production
- url: https://app.staging.sendo.so
description: Sandbox / staging (declared in Sendoso's own reference-page code samples)
externalDocs:
description: Sendoso REST API documentation
url: https://developer.sendoso.com/rest-api/overview/introduction
security:
- OAuth2: []
tags:
- name: Users
description: Read the authorized user, list organization users, invite new users.
- name: Teams
description: Team groups and their members.
- name: Campaigns
description: Campaigns, called "touches" in the API.
- name: Sends
description: Create and retrieve gift, direct mail and eGift sends.
paths:
/api/v3/me:
get:
operationId: getCurrentUser
summary: Get Current User
description: Get information about the current authorized user.
tags: [Users]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/users/get-current-user
responses:
'200':
description: The authorized user.
content:
application/json:
schema:
$ref: '#/components/schemas/CurrentUser'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/users:
get:
operationId: getUsers
summary: Get All Users
description: Retrieve a paginated list of all active users associated to the organization.
tags: [Users]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/users/get-users
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PerPage'
responses:
'200':
description: A page of users.
content:
application/json:
schema:
type: object
required: [current_page, per_page, total_users, users]
properties:
current_page:
type: integer
description: The current page being returned.
per_page:
type: integer
description: The number of results being returned per page.
total_users:
type: integer
description: The total number of users.
users:
type: array
items:
$ref: '#/components/schemas/User'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
post:
operationId: inviteUser
summary: Invite New User
description: Create a new user invitation for a specific team group.
tags: [Users]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/users/invite-user
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [user]
properties:
user:
type: object
required: [first_name, last_name, email, role, team_group_id]
properties:
first_name:
type: string
description: The new user's first name.
last_name:
type: string
description: The new user's last name.
email:
type: string
description: The new user's email address.
role:
type: string
enum: [regular, manager]
description: The new user's role.
team_group_id:
type: integer
description: >-
The ID of the team to invite the user to. Obtain it from
GET /api/v3/groups.
responses:
'201':
description: Invitation created.
content:
application/json:
schema:
type: object
required: [success, message, receiver_email, team_group_id, user_role, invitation_status, expires_at]
properties:
success:
type: boolean
message:
type: string
receiver_email:
type: string
team_group_id:
type: integer
user_role:
type: string
invitation_status:
type: string
enum: [pending, accepted, expired]
expires_at:
type: string
description: When the invitation expires, in ISO 8601 format.
'400':
description: >-
Bad request. Documented messages include "Please enter a valid team group" and
"Role can be one of these: manager,regular".
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/groups:
get:
operationId: getTeamGroups
summary: Get All Team Groups
description: Retrieve information of all the organization's active team groups.
tags: [Teams]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/teams/get-teams
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PerPage'
responses:
'200':
description: A page of team groups.
content:
application/json:
schema:
type: object
required: [current_page, per_page, total_groups, groups]
properties:
current_page:
type: integer
per_page:
type: integer
total_groups:
type: integer
groups:
type: array
items:
$ref: '#/components/schemas/TeamGroup'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/groups/{team_group_id}/members:
get:
operationId: getTeamGroupUsers
summary: Get All Team Group Users
description: Get the list of users for the specific team.
tags: [Teams]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/teams/get-team-users
parameters:
- name: team_group_id
in: path
required: true
description: The team group id to get the users from.
schema:
type: integer
responses:
'200':
description: Array of user objects.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/TeamGroupMember'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: 'Group not found. Documented body: {"message": "Group not found!"}'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/touches:
get:
operationId: getCampaigns
summary: Get All Campaigns
description: Retrieve a list of all active campaigns associated to the organization.
tags: [Campaigns]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/campaigns/get-campaigns
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PerPage'
- name: delivery_type
in: query
required: false
description: >-
Filter results by gift type. `mail` returns physical item campaigns, `email`
returns eGift campaigns.
schema:
type: string
enum: [mail, email]
responses:
'200':
description: A page of campaigns.
content:
application/json:
schema:
type: object
required: [current_page, per_page, total_posts, touches]
properties:
current_page:
type: integer
per_page:
type: integer
total_posts:
type: integer
description: The total number of campaigns.
touches:
type: array
items:
$ref: '#/components/schemas/Touch'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/touches/{touch_id}:
get:
operationId: getCampaign
summary: Get Campaign
description: Retrieve additional details on a specific campaign.
tags: [Campaigns]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/campaigns/get-campaign
parameters:
- name: touch_id
in: path
required: true
description: The campaign (touch) identifier.
schema:
type: integer
responses:
'200':
description: The campaign.
content:
application/json:
schema:
$ref: '#/components/schemas/Touch'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: 'Campaign not found. Documented message: "Touch not found".'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/send:
get:
operationId: getSends
summary: Retrieve All Sends
description: Retrieves a list of all sends initiated by anyone in the organization.
tags: [Sends]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/sends/get-sends
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PerPage'
responses:
'200':
description: A page of sends.
content:
application/json:
schema:
type: object
required: [current_page, per_page, total_count, sends]
properties:
current_page:
type: integer
per_page:
type: integer
total_count:
type: integer
sends:
type: array
items:
$ref: '#/components/schemas/Send'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
post:
operationId: createSend
summary: Create a Send
description: >-
Create a send. Sendoso documents three request shapes against this single path and
method, distinguished by the `via` discriminator and the address fields: a physical
gift to a known address, a physical gift with address collection, and an eGift sent
via Sendoso email. Sendoso does NOT deduplicate payloads — an identical request sent
twice creates two sends.
tags: [Sends]
externalDocs:
description: Send Physical Gift
url: https://developer.sendoso.com/rest-api/reference/sends/physical/physical
x-documented-variants:
- title: Send Physical Gift
url: https://developer.sendoso.com/rest-api/reference/sends/physical/physical
- title: Send Physical Gift with Address Collection
url: https://developer.sendoso.com/rest-api/reference/sends/physical/physicalAC
- title: Send eGift via Sendoso Email
url: https://developer.sendoso.com/rest-api/reference/sends/egift/eGift
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [send]
properties:
send:
oneOf:
- $ref: '#/components/schemas/PhysicalSendRequest'
- $ref: '#/components/schemas/PhysicalSendAddressCollectionRequest'
- $ref: '#/components/schemas/EgiftSendRequest'
responses:
'200':
description: Send created.
content:
application/json:
schema:
$ref: '#/components/schemas/SendResult'
'400':
description: 'Bad request. Documented message example: "email can''t be blank".'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: 'Campaign not found. Documented message: "Touch not found".'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
$ref: '#/components/responses/TooManyRequests'
/api/v3/send/generate_egift_links:
post:
operationId: generateEgiftLinks
summary: Generate eGift Links
description: >-
Generate one or more eGift links to embed in your own outreach to the recipient(s).
Each recipient gets a unique link associated to the email passed in the request.
tags: [Sends]
externalDocs:
url: https://developer.sendoso.com/rest-api/reference/sends/egift/eGiftlink
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [send]
properties:
send:
type: object
required: [touch_id, via, via_from, recipient_users]
properties:
touch_id:
type: integer
description: The ID of the campaign within Sendoso you want to send.
via:
type: string
const: generate_egift_links
via_from:
type: string
description: >-
The name of the application making the send request. Keep this
consistent per application.
recipient_users:
type: array
description: An array of recipient emails to generate links for.
items:
type: object
required: [email]
properties:
email:
type: string
responses:
'200':
description: Links generated.
content:
application/json:
schema:
type: object
required: [success, message, egift_links]
properties:
success:
type: boolean
message:
type: string
egift_links:
type: array
items:
type: object
required: [egift_link, recipient_email_or_phone_number]
properties:
egift_link:
type: string
description: The link generated for this specific recipient.
recipient_email_or_phone_number:
type: string
'400':
description: Bad request.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: 'Campaign not found. Documented message: "Touch not found".'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
$ref: '#/components/responses/TooManyRequests'
components:
securitySchemes:
OAuth2:
type: oauth2
description: >-
OAuth 2.0 Authorization Code grant. Register your application by contacting
developers@sendoso.com to receive a client ID and client secret. Access tokens live
7200 seconds (2 hours) and are refreshed at the same token endpoint. Tokens are sent
as `Authorization: Bearer <token>`.
flows:
authorizationCode:
authorizationUrl: https://app.sendoso.com/oauth/authorize
tokenUrl: https://app.sendoso.com/oauth/token
refreshUrl: https://app.sendoso.com/oauth/token
scopes:
public: Access the user's basic information.
write: Send gifts on the user's behalf.
update: Update the user's account details.
marketplace: Access the marketplace API.
smartsend: Access the smartsend API.
parameters:
Page:
name: page
in: query
required: false
description: The page number of the results you want to retrieve. The first page is 1.
schema:
type: integer
minimum: 1
PerPage:
name: per_page
in: query
required: false
description: The number of results to be returned per page. Max is 100.
schema:
type: integer
maximum: 100
responses:
Unauthorized:
description: 'Unauthorized. Documented message: "The access token is invalid".'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
TooManyRequests:
description: >-
Too Many Requests. Sendoso throttles application clients sending more than 10
requests/second; the client is temporarily blocked from making further requests.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
Error:
type: object
description: >-
Sendoso's error envelope. Not RFC 9457 problem+json — errors are returned as
`application/json` with a `success` flag and a human-readable `message`. Some
documented 401 bodies use `description` and `expired` instead of `message`.
properties:
success:
type: boolean
message:
type: string
description:
type: string
expired:
type: boolean
CurrentUser:
type: object
required: [id, first_name, last_name, email, role, balance, team_balance]
properties:
id:
type: integer
first_name:
type: string
last_name:
type: string
email:
type: string
role:
type: string
balance:
type: string
description: The user's personal balance.
team_balance:
type: integer
description: The sum of all the users' balance.
User:
type: object
required: [id, first_name, last_name, email, team_group_id]
properties:
id:
type: string
first_name:
type: string
last_name:
type: string
email:
type: string
team_group_id:
type: number
TeamGroupMember:
type: object
required: [id, first_name, last_name, email, balance, sandbox, team_group_id, team_id, key]
properties:
id:
type: string
first_name:
type: string
last_name:
type: string
email:
type: string
balance:
type: string
sandbox:
type: boolean
description: Whether this user is a sandbox user.
team_group_id:
type: integer
team_id:
type: integer
description: The team's organization id.
key:
type: string
description: The user's invitation key.
TeamGroup:
type: object
required: [id, budget, created_at, monthly_budget, name, one_time_budget, rollover, team_id, updated_at]
properties:
id:
type: string
budget:
type: integer
created_at:
type: string
description: ISO 8601.
monthly_budget:
type: string
name:
type: string
one_time_budget:
type: integer
rollover:
type: boolean
description: Whether the monthly budget rolls over to the next month.
team_id:
type: integer
description: The team group's organization id.
updated_at:
type: string
description: ISO 8601.
Touch:
type: object
description: A campaign. Called a "touch" throughout the API.
required: [id, name, start_date, description, created_at, user_id, gift_id, status, is_default_price, delivery_type]
properties:
id:
type: integer
name:
type: string
start_date:
type: string
description: ISO 8601. Gifts cannot be sent for this campaign before this date.
end_date:
type: string
description: ISO 8601. Gifts cannot be sent for this campaign after this date.
description:
type: string
created_at:
type: string
description: ISO 8601.
user_id:
type: integer
description: The identifier of the user that created this campaign.
gift_id:
type: integer
starting_egift_price:
type: number
description: Lower bound of the eGift denomination range. eGift campaigns only.
ending_egift_price:
type: number
description: Upper bound of the eGift denomination range. eGift campaigns only.
status:
type: string
description: Always `Active` — this endpoint only returns active campaigns.
is_default_price:
type: boolean
delivery_type:
type: string
enum: [mail, email]
description: '`mail` = physical item, `email` = eGift.'
Send:
type: object
required: [id, send_gid, type, subtype, currency, current_total_cost]
properties:
id:
type: integer
send_gid:
type: string
description: The gid of the send.
type:
type: string
description: >-
The send's type. Documented values: Amazon, Handwritten Notes, Inventoried Sends,
Sendoso Choice, Sendoso Direct, eGifts International, eGifts USA.
subtype:
type: string
description: >-
The send's subtype. Documented values include Bundles, Buy/Send via Amazon,
Coffee, Custom, Donate to Charity, Experiences, Handwritten Notes, Lunch,
On-Demand, Wine, and the per-country eGift Cards variants.
currency:
type: string
description: ISO 4217.
current_total_cost:
type: string
description: >-
The send's cost at the time of the request. May change until the send reaches a
final status.
PhysicalSendRequest:
title: Send Physical Gift
type: object
description: Send a physical item directly to a recipient when their address is known.
required: [touch_id, name, email, address, city, state, zip, country, confirm_address, via, via_from]
properties:
touch_id:
type: integer
name:
type: string
email:
type: string
address:
type: string
city:
type: string
state:
type: string
zip:
type: string
country:
type: string
mobile_no:
type: number
description: >-
Required for non-US addresses — a request without it will fail for any non-US
address.
custom_message:
type: string
description: The message that goes on the notecard in the gift box, if applicable.
confirm_address:
type: boolean
description: Send `false` when you are providing the recipient address.
via:
type: string
const: single_person_or_company
via_from:
type: string
PhysicalSendAddressCollectionRequest:
title: Send Physical Gift with Address Collection
type: object
description: Send a physical item when the recipient address is unknown.
required: [touch_id, name, email, no_address, confirm_address, address_confirmation_via, resume_with_unconfirmed_address, expire_after_days, hide_product_info, via, via_from]
properties:
touch_id:
type: integer
name:
type: string
email:
type: string
custom_message:
type: string
no_address:
type: boolean
const: true
confirm_address:
type: boolean
const: true
address_confirmation_via:
type: string
enum: [email, link]
description: >-
`email` sends the recipient an email; `link` returns a link in the response and
also mails a link to the sender.
resume_with_unconfirmed_address:
type: boolean
description: Sendoso documents leaving this FALSE for this endpoint.
expire_after_days:
type: integer
minimum: 2
maximum: 7
description: How many days the address collection form stays valid.
hide_product_info:
type: boolean
description: Whether the gift name and image appear on the address collection page.
address_confirmation_custom_message:
type: string
description: Only applicable when sending address collection via the email method.
via:
type: string
const: single_person_or_company
via_from:
type: string
EgiftSendRequest:
title: Send eGift via Sendoso Email
type: object
description: Send an eGift directly to a recipient.
required: [touch_id, email, via, via_from]
properties:
touch_id:
type: integer
name:
type: string
email:
type: string
custom_message:
type: string
description: The message that goes in the body of the eGift email.
via:
type: string
const: single_email_address
via_from:
type: string
SendResult:
type: object
required: [success, message, tracking_code]
properties:
success:
type: boolean
description: Always `true` for 2xx responses.
message:
type: string
tracking_code:
type: string
description: The send's unique tracking code.
tracking_url:
type: string
description: The send's unique tracking URL. Returned for eGift sends.