openapi: 3.0.3 info: title: Stannp Direct Mail API description: > REST API for programmatically sending physical letters and postcards, managing recipient groups, configuring campaigns, triggering individual mail pieces, and tracking delivery status through webhooks and event callbacks. Authentication uses API key-based HTTP Basic Auth over HTTPS. version: 1.0.0 contact: name: Stannp Support url: https://www.stannp.com/us/direct-mail-api/guide termsOfService: https://www.stannp.com servers: - url: https://api-us1.stannp.com/v1 description: US API server - url: https://api-eu1.stannp.com/v1 description: EU API server security: - basicAuth: [] paths: /accounts/balance: get: operationId: getAccountBalance summary: Get account balance description: Retrieve the current account balance. tags: - Account responses: '200': description: Account balance retrieved successfully content: application/json: schema: $ref: '#/components/schemas/BalanceResponse' '401': $ref: '#/components/responses/Unauthorized' /accounts/topup: post: operationId: topUpBalance summary: Top up account balance description: Add funds to the account balance. tags: - Account requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - net properties: net: type: string description: The amount to top up (e.g. "10.00"). Tax may be added after. example: "10.00" responses: '200': description: Balance topped up successfully content: application/json: schema: type: object properties: success: type: boolean data: type: object properties: receipt_pdf: type: string format: uri description: URL to the receipt PDF '401': $ref: '#/components/responses/Unauthorized' /users/me: get: operationId: getCurrentUser summary: Get current user description: Retrieve information about the currently authenticated user. tags: - Account responses: '200': description: User information retrieved successfully content: application/json: schema: $ref: '#/components/schemas/UserResponse' '401': $ref: '#/components/responses/Unauthorized' /postcards/create: post: operationId: createPostcard summary: Create a postcard description: > Create and dispatch a single postcard. Use test=true to generate a preview PDF without charges. tags: - Postcards requestBody: required: true content: multipart/form-data: schema: type: object properties: size: type: string enum: - 4x6 - 6x9 - 6x11 default: 4x6 description: Postcard size (US formats) test: type: boolean description: Produce sample PDF without dispatch or charges template: type: integer description: Template ID from the platform recipient: description: Existing recipient ID or new recipient object oneOf: - type: integer description: Existing recipient ID - $ref: '#/components/schemas/RecipientInput' message: type: string description: Text overlay on postcard back front: type: string format: uri description: URL to JPG, PNG, or PDF for the front design back: type: string format: uri description: URL to JPG, PNG, or PDF for the back design padding: type: integer description: White border control; 0 removes the default border post_unverified: type: boolean default: true description: Prevents posting if address is unverified clearzone: type: boolean description: Overlays clear zones with white background return_address: type: string description: Custom return address tags: type: string description: Comma-separated searchable tags addons: type: string description: Upgrade codes (e.g. FIRST_CLASS) idempotency_key: type: string description: Key for safe request retries responses: '200': description: Postcard created successfully content: application/json: schema: $ref: '#/components/schemas/MailpieceResponse' '401': $ref: '#/components/responses/Unauthorized' /postcards/get/{id}: get: operationId: getPostcard summary: Get a postcard description: Retrieve details of a single postcard mailpiece. tags: - Postcards parameters: - name: id in: path required: true schema: type: integer description: Mailpiece ID responses: '200': description: Postcard details retrieved content: application/json: schema: $ref: '#/components/schemas/MailpieceResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /postcards/cancel: post: operationId: cancelPostcard summary: Cancel a postcard description: Cancel a postcard that has not yet been dispatched. tags: - Postcards requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Mailpiece ID to cancel responses: '200': description: Postcard cancelled successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /letters/create: post: operationId: createLetter summary: Create a letter (template/HTML) description: > Create and dispatch a single letter using a template or HTML content. Use test=true to generate a preview PDF without charges. tags: - Letters requestBody: required: true content: multipart/form-data: schema: type: object properties: test: type: boolean description: Produce sample PDF without dispatch or charges idempotency_key: type: string description: Key for safe request retries template: type: integer description: Template ID for mail merge background: type: string format: uri description: URL to background image or PDF pages: type: string description: HTML content for letter pages recipient: description: Existing recipient ID or new recipient object oneOf: - type: integer description: Existing recipient ID - $ref: '#/components/schemas/RecipientInput' size: type: string enum: - US-LETTER - US-LETTER-XL-WINDOW description: Letter size duplex: type: boolean description: Enable front/back printing addons: type: string description: Upgrade codes (e.g. FIRST_CLASS, CONFIDENTIAL) tags: type: string description: Comma-separated searchable tags responses: '200': description: Letter created successfully content: application/json: schema: $ref: '#/components/schemas/MailpieceResponse' '401': $ref: '#/components/responses/Unauthorized' /letters/post: post: operationId: postLetter summary: Post a pre-merged letter (PDF) description: Dispatch a letter using a pre-merged PDF file. tags: - Letters requestBody: required: true content: multipart/form-data: schema: type: object required: - country properties: country: type: string description: ISO alpha-2 country code (US, CA, GB, etc.) example: US pdf: type: string format: uri description: URL or binary PDF file (max 25 pages) test: type: boolean description: Sample mode - no dispatch or charges addons: type: string description: Upgrade codes (e.g. FIRST_CLASS, CONFIDENTIAL) transactional: type: boolean description: Mark as transactional for sensitive data handling responses: '200': description: Letter posted successfully content: application/json: schema: $ref: '#/components/schemas/MailpieceResponse' '401': $ref: '#/components/responses/Unauthorized' /letters/get/{id}: get: operationId: getLetter summary: Get a letter description: Retrieve details of a single letter mailpiece. tags: - Letters parameters: - name: id in: path required: true schema: type: integer description: Mailpiece ID responses: '200': description: Letter details retrieved content: application/json: schema: $ref: '#/components/schemas/MailpieceResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /letters/cancel: post: operationId: cancelLetter summary: Cancel a letter description: Cancel a letter that has not yet been dispatched. tags: - Letters requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Mailpiece ID to cancel responses: '200': description: Letter cancelled successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /recipients/list: get: operationId: listRecipients summary: List recipients description: Retrieve a paginated list of recipients, optionally filtered by group. tags: - Recipients parameters: - name: group_id in: query schema: type: integer description: Filter by group ID - name: offset in: query schema: type: integer description: Pagination offset - name: limit in: query schema: type: integer description: Number of results to return responses: '200': description: Recipients retrieved successfully content: application/json: schema: type: object properties: success: type: boolean data: type: array items: $ref: '#/components/schemas/Recipient' '401': $ref: '#/components/responses/Unauthorized' /recipients/get/{id}: get: operationId: getRecipient summary: Get a recipient description: Retrieve details of a single recipient. tags: - Recipients parameters: - name: id in: path required: true schema: type: integer description: Recipient ID responses: '200': description: Recipient retrieved successfully content: application/json: schema: type: object properties: success: type: boolean data: $ref: '#/components/schemas/Recipient' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /recipients/new: post: operationId: createRecipient summary: Create a recipient description: Add a new recipient, optionally to a mailing group. tags: - Recipients requestBody: required: true content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/RecipientInput' responses: '200': description: Recipient created successfully content: application/json: schema: type: object properties: success: type: boolean data: type: object properties: id: type: string description: New recipient ID valid: type: boolean description: Whether the address is valid created: type: string format: date-time '401': $ref: '#/components/responses/Unauthorized' /recipients/delete: post: operationId: deleteRecipient summary: Delete a recipient description: Permanently delete a recipient record. tags: - Recipients requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Recipient ID to delete responses: '200': description: Recipient deleted successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /recipients/import: post: operationId: importRecipients summary: Import recipients from file description: Bulk import recipients from a CSV or XLS file into a group. tags: - Recipients requestBody: required: true content: multipart/form-data: schema: type: object required: - file - group_id properties: file: type: string format: binary description: CSV or XLS file (binary, base64, or URL) group_id: type: integer description: Group to import recipients into duplicates: type: string enum: - update - ignore - duplicate description: How to handle duplicate recipients no_headings: type: boolean description: Set true if the file has no header row mappings: type: string description: Column remapping instructions responses: '200': description: Import initiated successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /groups/list: get: operationId: listGroups summary: List groups description: Retrieve a paginated list of recipient groups. tags: - Groups parameters: - name: offset in: query schema: type: integer description: Pagination offset - name: limit in: query schema: type: integer description: Number of results to return responses: '200': description: Groups retrieved successfully content: application/json: schema: type: object properties: success: type: boolean data: type: array items: $ref: '#/components/schemas/Group' '401': $ref: '#/components/responses/Unauthorized' /groups/new: post: operationId: createGroup summary: Create a group description: Create a new recipient group. tags: - Groups requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - name properties: name: type: string description: Group name responses: '200': description: Group created successfully content: application/json: schema: type: object properties: success: type: boolean data: type: integer description: New group ID '401': $ref: '#/components/responses/Unauthorized' /groups/add/{group_id}: post: operationId: addRecipientsToGroup summary: Add recipients to group description: Add one or more existing recipients to a group. tags: - Groups parameters: - name: group_id in: path required: true schema: type: integer description: Group ID requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - recipients properties: recipients: type: string description: Comma-separated recipient IDs responses: '200': description: Recipients added successfully content: application/json: schema: type: object properties: success: type: boolean data: type: integer description: Number of recipients added '401': $ref: '#/components/responses/Unauthorized' /groups/remove/{group_id}: post: operationId: removeRecipientsFromGroup summary: Remove recipients from group description: Remove one or more recipients from a group. tags: - Groups parameters: - name: group_id in: path required: true schema: type: integer description: Group ID requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - recipients properties: recipients: type: string description: Comma-separated recipient IDs responses: '200': description: Recipients removed successfully content: application/json: schema: type: object properties: success: type: boolean data: type: integer description: Number of recipients removed '401': $ref: '#/components/responses/Unauthorized' /groups/purge: post: operationId: purgeGroup summary: Purge a group description: Remove all recipients from a group, optionally deleting recipient records. tags: - Groups requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Group ID delete_recipients: type: boolean description: If true, delete all recipient records in the group responses: '200': description: Group purged successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /groups/calculate/{group_id}: post: operationId: recalculateGroup summary: Recalculate group description: Trigger a recalculation of group recipient counts and validity. tags: - Groups parameters: - name: group_id in: path required: true schema: type: integer description: Group ID responses: '200': description: Recalculation triggered successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /groups/delete: post: operationId: deleteGroup summary: Delete a group description: Delete a recipient group, optionally deleting associated recipient records. tags: - Groups requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Group ID delete_recipients: type: boolean description: If true, also delete all recipients in the group responses: '200': description: Group deleted successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /campaigns/list: get: operationId: listCampaigns summary: List campaigns description: Retrieve a list of all campaigns. tags: - Campaigns responses: '200': description: Campaigns retrieved successfully content: application/json: schema: type: object properties: success: type: boolean data: type: array items: $ref: '#/components/schemas/Campaign' '401': $ref: '#/components/responses/Unauthorized' /campaigns/get/{id}: get: operationId: getCampaign summary: Get a campaign description: Retrieve details of a single campaign. tags: - Campaigns parameters: - name: id in: path required: true schema: type: integer description: Campaign ID responses: '200': description: Campaign retrieved successfully content: application/json: schema: type: object properties: success: type: boolean data: $ref: '#/components/schemas/Campaign' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /campaigns/create: post: operationId: createCampaign summary: Create a campaign description: Create a new direct mail campaign targeting a recipient group. tags: - Campaigns requestBody: required: true content: multipart/form-data: schema: type: object required: - name - type - group_id properties: name: type: string description: Campaign name type: type: string enum: - a6-postcard - a5-postcard - letter description: Campaign type template_id: type: integer description: Template ID to use for the campaign file: type: string format: uri description: URL to PDF file for letters front: type: string format: uri description: URL to front design for postcards back: type: string format: uri description: URL to back design for postcards size: type: string description: Mail piece size (when using files) save: type: boolean description: Save the campaign as a draft group_id: type: integer description: ID of the recipient group what_recipients: type: string description: "Filter: all, valid, not_valid, or integer count" addons: type: string description: Upgrade codes (e.g. FIRST_CLASS) responses: '200': description: Campaign created successfully content: application/json: schema: type: object properties: success: type: boolean data: $ref: '#/components/schemas/Campaign' '401': $ref: '#/components/responses/Unauthorized' /campaigns/sample: post: operationId: getCampaignSample summary: Get campaign sample description: Generate a sample PDF for the campaign (valid for 30 minutes). tags: - Campaigns requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Campaign ID responses: '200': description: Sample PDF generated content: application/json: schema: type: object properties: success: type: boolean data: type: string format: uri description: URL to sample PDF (valid for 30 minutes) '401': $ref: '#/components/responses/Unauthorized' /campaigns/approve: post: operationId: approveCampaign summary: Approve a campaign description: Approve a campaign, making it ready for booking. tags: - Campaigns requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Campaign ID responses: '200': description: Campaign approved successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /campaigns/cost: post: operationId: getCampaignCost summary: Get campaign cost description: Calculate the cost of a campaign including recipient breakdown and VAT. tags: - Campaigns requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Campaign ID responses: '200': description: Campaign cost calculated content: application/json: schema: type: object properties: success: type: boolean data: type: object properties: rate: type: string description: Per-item rate valid: type: integer description: Count of valid recipients invalid: type: integer description: Count of invalid recipients total: type: string description: Total cost before tax total_with_vat: type: string description: Total cost including VAT '401': $ref: '#/components/responses/Unauthorized' /campaigns/availableDates: post: operationId: getCampaignAvailableDates summary: Get available booking dates description: Retrieve available dates on which a campaign can be dispatched. tags: - Campaigns requestBody: required: false content: application/x-www-form-urlencoded: schema: type: object properties: start: type: string format: date description: Start of date range (YYYY-MM-DD) end: type: string format: date description: End of date range (YYYY-MM-DD) responses: '200': description: Available dates retrieved content: application/json: schema: type: object properties: success: type: boolean data: type: array items: type: string format: date '401': $ref: '#/components/responses/Unauthorized' /campaigns/book: post: operationId: bookCampaign summary: Book a campaign description: Schedule a campaign for dispatch on a specific date. tags: - Campaigns requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id - send_date properties: id: type: integer description: Campaign ID send_date: type: string format: date description: Dispatch date (YYYY-MM-DD) next_available_date: type: boolean default: true description: Use next available date if chosen date is unavailable use_balance: type: boolean default: true description: Pay from account balance responses: '200': description: Campaign booked successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /campaigns/delete: post: operationId: deleteCampaign summary: Delete a campaign description: Permanently delete a campaign. tags: - Campaigns requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: integer description: Campaign ID responses: '200': description: Campaign deleted successfully content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' /recipientEvents/create: post: operationId: createRecipientEvent summary: Create a recipient event description: > Record an engagement or conversion event for a recipient (e.g. PURCHASE, SIGNUP, PAGE_VIEW). Can be used to trigger automation and dynamic templating. tags: - Events requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: - recipient_id - name properties: recipient_id: type: string description: Recipient ID or alternative reference ID name: type: string description: Event name (e.g. PURCHASE, SIGNUP, PAGE_VIEW, PRODUCT_VIEW, PRODUCT_TO_BASKET) example: PURCHASE value: type: string description: Value information (e.g. purchase amount or product name) conversion: type: boolean default: false description: Whether this is a conversion event data: type: string description: Extended JSON data for automation or dynamic templating ref: type: string description: Campaign or mailpiece reference ID; recent communications used if omitted responses: '200': description: Event created successfully content: application/json: schema: type: object properties: success: type: boolean data: type: integer description: New event ID '401': $ref: '#/components/responses/Unauthorized' components: securitySchemes: basicAuth: type: http scheme: basic description: Use your API key as the username and leave the password blank. schemas: RecipientInput: type: object properties: group_id: type: integer description: Group to add the recipient to title: type: string description: Title (Mr, Mrs, Dr, etc.) firstname: type: string lastname: type: string company: type: string job_title: type: string address1: type: string description: First line of address address2: type: string address3: type: string city: type: string county: type: string description: State or county postcode: type: string description: Postcode or ZIP code zipcode: type: string description: ZIP code (US alternative to postcode) country: type: string description: ISO 3166-1 Alpha-2 country code example: US email: type: string format: email phone_number: type: string ref_id: type: string description: Custom external reference ID on_duplicate: type: string enum: - update - ignore - duplicate description: Behaviour when duplicate is found test_level: type: string enum: - email - fullname - initial - ref_id description: Field(s) used to detect duplicates Recipient: type: object properties: id: type: integer account_id: type: integer title: type: string firstname: type: string lastname: type: string company: type: string job_title: type: string address1: type: string address2: type: string address3: type: string city: type: string county: type: string country: type: string zipcode: type: string dps: type: string description: Delivery Point Suffix email: type: string phone_number: type: string ref_id: type: string blacklist: type: boolean description: Whether recipient is on the block list created: type: string format: date-time updated: type: string format: date-time Group: type: object properties: id: type: integer account_id: type: integer name: type: string created: type: string format: date-time recipients: type: integer description: Total recipient count valid: type: integer description: Count of valid addresses international: type: integer description: Count of international addresses skipped: type: integer status: type: string import_progress: type: integer description: Import progress percentage is_seeds: type: boolean Campaign: type: object properties: id: type: integer name: type: string type: type: string enum: - a6-postcard - a5-postcard - letter status: type: string recipients: type: integer cost: type: string created: type: string format: date-time MailpieceResponse: type: object properties: success: type: boolean data: type: object properties: id: type: integer description: Mailpiece ID pdf: type: string format: uri description: URL to the proof PDF created: type: string format: date-time format: type: string description: Mail piece format/size cost: type: string description: Cost of the mailpiece status: type: string description: Current status tracking_reference: type: string description: Carrier tracking reference dispatched: type: string format: date-time description: Dispatch timestamp SuccessResponse: type: object properties: success: type: boolean data: description: Result value (boolean, integer, or string depending on operation) BalanceResponse: type: object properties: success: type: boolean data: type: object properties: balance: type: string description: Current account balance as a decimal string example: "150.00" UserResponse: type: object properties: success: type: boolean data: type: object description: Current user account details ErrorResponse: type: object properties: success: type: boolean example: false error: type: string description: Error message responses: Unauthorized: description: Authentication required or API key invalid content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' tags: - name: Account description: Account balance and user information - name: Postcards description: Create, retrieve, and cancel postcard mailpieces - name: Letters description: Create, post, retrieve, and cancel letter mailpieces - name: Recipients description: Manage individual recipients and bulk imports - name: Groups description: Manage recipient groups - name: Campaigns description: Manage batch direct mail campaigns - name: Events description: Record recipient engagement and conversion events