Sendoso Core API

Create physical gift, direct mail and eGift sends against Sendoso campaigns, and read the campaigns, users and team groups behind them. Ten operations on /api/v3.

OpenAPI Specification

sendoso-core-api-openapi.yml Raw ↑
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.