API Reference
Interactive reference rendered from the OpenAPI 3 spec. Every endpoint, request schema, and response is here — with multi-language code samples and a try-it client. The spec is the source of truth at openapi.yaml.
All endpoints at a glance (text index)
Plain-text list of every endpoint, searchable from the box above. Click one to open it in the interactive reference below.
eCards
GET/pub/ecard-actions/get-ecards List eCards in a widget
Returns the enabled eCards in a widget, with their names, HTML bodies, and image URLs. Use the returned `ecardid` (and the `widgetId` you passed) with **Send eCard**.
Parameters: widgetId (query): The widget's vanity ID (e.g. `w6v62rn95yq`).
POST/pub/ecard-actions/send-ecard Send, schedule, or share an eCard
Sends an eCard one of three ways: - **Email now** — the default. Emails the eCard to `recipientEmail`. - **Schedule** — set a *future* `sendAt`; it sends automatically at that time. - **Share link** — set `type` to `ecard_copy_link` (or `is_sharing: true`). Instead of emailing, it creates a viewable eCard and returns a **`shareUrl`** you can route anywhere (Slack, SMS, a CRM note). No email is sent, so `recipientEmail` is optional in this mode. **Required:** `ecardId`, `senderEmail`, `senderName`, `recipientName`. `recipientEmail` is required for email sends and optional for share links. > This endpoint returns a **flat** object (no `data` envelope). Email sends include > `emailsSent`; share sends include `statVanityId` + `shareUrl`.
GET/ecard/findOne/id/{id} Get one eCard
The full configuration for one eCard design. Requires the `ecards` key scope.
Parameters: id (path)
POST/ecard/save Create or update an eCard
Create an eCard (omit `myEcard.id`) or update one (send its real `myEcard.id`). `myEcard.name` is required and every eCard belongs to a widget via `myEcard.widgetid`. Supply artwork **either** as a public URL (`myEcard.self_hosted_url`) **or** a base64 blob in the top-level `ecardimg` field (raw or `data:` URI) — the blob is uploaded and stored as the cover image. `myEcard.details` is the eCard body HTML (sanitized server-side). Requires the `ecards: manage` scope.
Request body (application/json): myEcard, ecardimg (Optional eCard image as base64 (raw or `data:image/...;base64,` URI). Alternative to `myEcard.self_hosted_url`.)
POST/ecard/deleteEcards Delete eCards
Permanently delete one or more eCards. An eCard that is in use may require confirmation in the dashboard (`403` with `requires_otp`). Requires the `ecards: manage` scope.
Request body (application/json): ecardids (Numeric eCard ids to delete.)
POST/ecard/copy Duplicate an eCard
Copy an eCard (its design + image). By default the copy lands in the source eCard's widget; pass `widgetid` to place it in a different widget you own. Requires the `ecards: manage` scope.
Request body (application/json): ecardid (Source eCard id to copy.), widgetid (Optional target widget id (default: the source's widget).)
POST/ecard/bulkUpdate Bulk-update one field across a widget's eCards
Set a single whitelisted field to the same value across every eCard in a widget (or an explicit `ecardids` list). Allowed `fieldName` values: `name`, `emailSubject`, `header`, `details`, `ecardLink`, `url_redirect_after_send`, `disabled`, `canSchedule`, `ecardbrandid`, `ecard_mode`, `envelope_bg_image_url`, `envelope_color_settings`, `envelope_auto_open`, `envelope_confetti`, `envelope_audio_url`, `envelope_video_url`. Campaign-backed widgets are rejected. Requires the `ecards: manage` scope.
Request body (application/json): widgetid (Apply to all eCards in this widget.), ecardids (Or apply to these specific eCard ids.), fieldName (The whitelisted field to set (see list above).), fieldValue (The value to set on every targeted eCard.)
POST/ecard/saveOrder Reorder eCards
Set the display order of eCards within a widget. Requires the `ecards: manage` scope.
Request body (application/json): neworder (eCard ids in the desired order.)
POST/ecard/uploadMediaImage Upload a media image
Upload a base64 image and get back a hosted URL you can reference from an eCard (e.g. as `self_hosted_url`, or inside `details` HTML). Requires the `ecards: manage` scope.
Request body (application/json): imageBase (Image as base64 (raw or `data:` URI).)
POST/ecard/preview Preview an eCard render
Render a preview of an eCard with optional merge-tag values and property overrides, without sending anything. Requires the `ecards` key scope.
Request body (application/json): id (eCard id to preview.), mergeTags (Key/value merge-tag values to fill.), overrideProps (Ad-hoc property overrides for the preview.), trialMode (Render in trial/watermark mode.)
eCard Search
GET/ecard/search Search eCard designs (beta)
Search and page through the eCard designs in your account. > **In active development (beta).** Authenticate with your **API key** as a Bearer > token (`Authorization: Bearer YOUR_API_KEY`), the same as every other endpoint. For a lighter, > widget-scoped listing, use `GET /pub/ecard-actions/get-ecards` instead.
Parameters: page (query): Page number; perPage (query): Results per page; keyword (query): Free-text search over eCard name/details; widgetID (query): Limit to a widget (0 = all); ecardIDs (query): Comma-separated eCard IDs (numeric or vanity); filterByDate (query): Date-range filter (e.g. any-time, last-week); sortBy (query): Sort order; includeCampaign (query): Include eCards from campaign widgets (excluded by default)
Widgets
GET/widget/search List / search widgets
Paginated list of your widgets. Requires the `widgets` key scope.
Parameters: page (query); perPage (query); keyword (query): Matches the widget name.; sortBy (query); sortOrder (query)
GET/widget/findOne/id/{id} Get one widget
The full configuration for one widget, including its parsed `wconfig`.
Parameters: id (path)
POST/widget/save Create or update a widget
Create a widget (send `widget.id: 0`) or update one (send its real `widget.id`). The `widget.name` and `widget.wconfig` fields are always required — `wconfig` is the widget's display/behavior config object and is stored as JSON. On create, the server assigns `id`, `vanity_id`, and `ownerid`. Disabling `dir_sender_must_be_in_directory` on an existing widget is OTP-gated (pass `otp_confirmation_token`). Requires the `widgets: manage` scope.
Request body (application/json): widget, ecardPrices (Optional map of `ecardId → price` to update per-eCard prices on this widget.), otp_confirmation_token (Required only when disabling `dir_sender_must_be_in_directory` on an existing widget.)
POST/widget/deleteWidgets Delete widgets
Permanently delete one or more widgets (and their eCards). A widget that is **in use** — attached to automations or campaigns, or with send history — cannot be deleted over the API: the response is `403` with `requires_otp` and an `impact` summary, and the deletion must be confirmed in the dashboard. Requires the `widgets: manage` scope.
Request body (application/json): widgetids (Numeric widget ids to delete.), otp_confirmation_token (Dashboard-issued confirmation token, required when a widget is in use.)
POST/widget/copyWidgetWithEcards Duplicate a widget (with its eCards)
Create a new widget by duplicating an existing one, copying its settings and (optionally a capped number of) its eCards. The copy is named `Copy - <source name>`. Requires the `widgets: manage` scope.
Request body (application/json): widgetid (Source widget id to duplicate.), limit (Optional cap on how many eCards to copy (default: all).)
Campaigns
GET/campaign/list List campaigns
Paginated list of your campaigns. Requires the `campaigns` key scope.
Parameters: page (query); perPage (query); keyword (query): Matches the campaign name.; status (query)
GET/campaign/findOne/id/{id} Get one campaign
The full configuration for one campaign, including its counts and schedule.
Parameters: id (path)
POST/campaign/save Create or update a campaign
Create a campaign (omit `campaign.id`) or update one (send its real `campaign.id`). Creating a campaign yields a **draft** — it does not send. `campaign_name` is required. After saving, attach eCards (`/campaign/saveCampaignEcards`) and recipients (`/campaign/saveRecipients`), then `/campaign/schedule` or `/campaign/send`. Requires the `campaigns: manage` scope.
Request body (application/json): campaign
POST/campaign/saveCampaignEcards Attach eCards to a campaign
Set which eCards the campaign sends. Requires the `campaigns: manage` scope.
Request body (application/json): campaignid, ecardIds (eCard ids to include.)
POST/campaign/saveRecipients Set campaign recipients
Set the campaign's recipients from directory members (`directoryMemberIds`) and/or an array of CSV rows (`csvRecipients`). Requires the `campaigns: manage` scope.
Request body (application/json): campaignid, directoryMemberIds (Directory member ids to target.), csvRecipients (Recipient rows (name/email/merge fields).)
POST/campaign/uploadCsv Upload a recipient CSV
Parse a recipient CSV (raw content in `csvContent`) into rows you can pass to /campaign/saveRecipients. Requires the `campaigns: manage` scope.
Request body (application/json): csvContent (Raw CSV text (with a header row).)
GET/campaign/recipients List a campaign's recipients
The recipients currently attached to a campaign. Requires the `campaigns` key scope.
Parameters: campaignid (query)
POST/campaign/schedule Schedule a campaign
Schedule the campaign to send at a future time. Sets status to `scheduled`. Requires the `campaigns: manage` scope.
Request body (application/json): campaignid, scheduled_at (Future send time.), scheduled_timezone (IANA timezone, e.g. America/Chicago.)
POST/campaign/send Send a campaign now
Send the campaign to all its recipients immediately. **Gift-card campaigns are OTP-gated**: if `gift_card_enabled` is set, the request must include a dashboard-issued `gc_confirmation_token`, otherwise it returns `403` with `requires_otp` and must be sent from the dashboard. Requires the `campaigns: manage` scope.
Request body (application/json): campaignid, gc_confirmation_token (Required only for gift-card-enabled campaigns.)
POST/campaign/updateLocale Set a campaign's locale
Set the render language for the campaign's eCards. Requires the `campaigns: manage` scope.
Request body (application/json): campaignid, locale
POST/campaign/delete Delete a campaign
Delete a campaign. This action is **OTP-gated**: over the API a key receives `403` with `requires_otp`, and the deletion must be confirmed in the dashboard. Requires the `campaigns: manage` scope.
Request body (application/json): id
Directory Sync
POST/pub/team-member-actions/upsert Create or update a team member
Adds a member, or updates them if they already exist. - **PATCH semantics** — only the fields you send change; omitted fields are left untouched, so a partial sync never blanks existing data. To clear a field, send it as an empty string. - **Matching** — by default members match by `email`. To survive email changes, send a stable `employee_id` and set `match_field: employee_id`; then an email change updates the same person instead of creating a duplicate. - **Departments** auto-create by name; **manager** is linked by email (resolves on a later sync if the manager isn't in the directory yet). - Use **`dry_run: true`** to validate field mappings and see the would-be action without saving.
GET/pub/team-member-actions/find Find a team member
Looks up a single member by `email` or `employee_id`. `data` is empty when not found.
Parameters: email (query): Match by email; employee_id (query): Match by employee/external ID
GET/pub/team-member-actions/list List team members (paginated)
Pages through your directory — use it to **reconcile**: periodically list members, diff against your source system, and `deactivate` anyone no longer present (the streaming-safe replacement for a spreadsheet "Sync" that deletes everyone not in the file). Paginate with the **cursor**: pass the previous page's `meta.next_after_id` as `after_id` until `meta.has_more` is `false`. Use `updated_since` for delta pulls.
Parameters: status (query): Which members to include.; perPage (query): Page size (max 500).; after_id (query): Cursor — the previous page's meta.next_after_id.; updated_since (query): ISO datetime — only members changed since then.
POST/pub/team-member-actions/deactivate Deactivate a team member (reversible)
Reversibly deactivates a member by `email` or `employee_id`. They stop receiving automated cards and **no longer count toward your seat limit**, but their record and history are kept. Use this for normal offboarding; reactivate to restore (subject to seat availability).
POST/pub/team-member-actions/reactivate Reactivate a deactivated team member
Reactivates a previously deactivated member by `email` or `employee_id` (needs an available seat).
POST/pub/team-member-actions/delete Permanently delete a team member (GDPR erasure)
**Irreversible.** Permanently removes a member and their data — for GDPR erasure only. For normal offboarding use **Deactivate** instead.
Field discovery
GET/pub/team-member-actions/fields List mappable fields
Returns the fields you can set on a member — standard fields plus your account's active **custom date fields** — each with a `label`, `type`, whether it's `required`, and the accepted `format`. Use this to drive field mapping in your integration.
GET/pub/team-member-actions/departments List departments
Returns your account's departments. (Departments are also auto-created by name on upsert.)
GET/pub/team-member-actions/sample Sample member-change event (Zapier helper)
Returns a single representative member-change event for the given `event_type`. This is a helper the **Zapier** integration uses to populate sample data and field mappings in the Zap editor — it isn't needed for normal API integrations.
Parameters: event_type (query): Which event shape to sample.
Webhooks
POST/pub/team-member-actions/subscribe Subscribe to a member-change event
Registers a `hookUrl` to receive a signed JSON `POST` whenever the chosen `event_type` happens. Returns a subscription `id` (use it to unsubscribe). **Event types:** `team_member_created`, `team_member_updated`, `team_member_deactivated`, `team_member_deleted`. `team_member_updated` fires **only on a real change** (idempotent re-syncs don't notify). The initial spreadsheet import does **not** emit events. **Delivery & signing:** each delivery is signed with your account's webhook secret (`X-ECW-Signature: t=<unix>,v1=<hex HMAC-SHA256>`, signed value `<t>.<raw body>`) and retried on failure. De-duplicate with the payload's `event_id`. See the `WebhookDelivery` schema for the payload shape.
Request body (application/json): event_type, hookUrl
POST/pub/team-member-actions/unsubscribe Remove a webhook subscription
Removes a subscription by the `id` returned from subscribe.
Request body (application/json): id
Automations
GET/automation/list List automations
Paginated list of your automations. Requires the `automations` key scope.
Parameters: page (query); perPage (query); keyword (query): Matches automation name, from-name, or from-email.; eventType (query): One of: birthday, anniversary, holiday, fixed_date, custom_field, rule_based, onboarding.; sortBy (query); sortOrder (query); status (query): Filter by the enabled flag.
GET/automation/findOne/id/{id} Get one automation
The full configuration for one automation, including its milestones (offsets/schedule).
Parameters: id (path)
POST/automation/toggle Enable or disable an automation
Turn an automation on or off. Enabling validates the configuration first.
Request body (application/json): automation
POST/automation/save Create or update an automation
Create an automation (omit `automation.id`) or update one (send its real `automation.id`; sending only `id` + `enabled` performs a partial enable/disable). `automation_name` and `event_type` are required on create. The JSON fields `trigger_config`, `timing_config`, `random_messages`, `selected_ecard_ids`, `selected_member_ids`, `selected_department_ids`, and `milestone_rules` are sent as objects/arrays. Creating a **gift-card** automation is OTP-gated in the dashboard. Requires the `automations: manage` scope.
Request body (application/json): automation, gc_confirmation_token (Required only when creating/enabling a gift-card automation.)
POST/automation/delete Delete an automation
Delete an automation. This action is **OTP-gated**: over the API a key receives `403` with `requires_otp`, and the deletion must be confirmed in the dashboard. Requires the `automations: manage` scope.
Request body (application/json): id
POST/automation/previewTrigger Preview an automation trigger
Resolve the next firing dates for a trigger/timing config without saving — useful to validate a rule before creating the automation. Requires the `automations` key scope.
Request body (application/json): trigger_type, trigger_config (The rule/date configuration to resolve.), timing_config (Offset/schedule configuration.)
POST/automation/saveNotificationEcards Set an automation's notification eCards
Set the eCards used for an automation's manager/department/segment notifications. Requires the `automations: manage` scope.
Request body (application/json): automation_id, notification_type, ecardIds
GET/automation/getNotificationEcards Get an automation's notification eCards
The notification eCards configured for an automation. Requires the `automations` key scope.
Parameters: id (query); notification_type (query)
POST/automation/deleteNotificationEcards Clear an automation's notification eCards
Remove the notification eCards for an automation. Requires the `automations: manage` scope.
Request body (application/json): automation_id
Gift Cards & Rewards
GET/gift-card/getSettings Get reward account settings
Your reward configuration (provider mode, per-card bounds, velocity enforcement flag). Requires the `gift_cards` key scope.
GET/gift-card/listProducts List available reward products
The reward brands/products available to your account (Giftbit catalog, or the brands in your manual pool).
Parameters: country (query): Optional ISO country filter.
GET/gift-card/listOrders List reward orders (paginated)
Reward orders across all send surfaces (widget, campaign, automation). Reward codes/links are masked. Do NOT pass `ownerid`/`user_id` — the account is derived from your key.
Parameters: page (query); perPage (query); payment_status (query); fulfillment_status (query); claim_status (query); scope (query); campaign_id (query); automation_id (query); dateFrom (query); dateTo (query)
GET/gift-card/getRules Get velocity / spend limits + usage
Configured spend guardrails and current usage. Read-only via API (changes are OTP-gated in the dashboard). Usage is tracked regardless of enforcement — check `getSettings.velocity_limits_enabled` to know whether limits are actually applied.
GET/gift-card/rewardInventory Manual-pool inventory
Remaining manual reward codes by brand/denomination. Use to alert before a pool runs dry.
GET/gift-card/analytics Reward analytics summary
Aggregate reward metrics (counts/totals by status, claim rate, spend). Pair with listOrders for detail.
Introspection
GET/key/info What can this key do?
Returns the **calling API key's own** capabilities — which feature areas it can read/write, the request rate limit, and usage this hour. Safe and non-sensitive: it never returns the key value, any other key, or account PII beyond the owner's own display name. Any valid key can call it regardless of scope (an all-`none` key still reads its own info). The `permissions` map resolves all 12 feature areas to `none` / `view` / `manage`; `capabilities` flattens that to `"<area>:read"` / `"<area>:write"` strings. `full_access: true` (a legacy/unscoped key) means `manage` everywhere.