{"openapi":"3.1.0","info":{"title":"7Stamp Integration API","description":"The **7Stamp Integration API** lets external systems (CRMs, e‑commerce, POS,\nautomation tools) manage 7Stamp loyalty cards using **your own contact\nidentifier** (`external_id`) instead of our internal IDs.\n\n## Authentication\nSend your key as a Bearer token:\n\n```\nAuthorization: Bearer <YOUR_API_KEY>\n```\n\nCreate a key in your dashboard: **API Integrations → API Keys → Add API Key**.\nA key belongs to a workplace and scopes all operations to that workplace's profile.\n\n## The `external_id` concept\nPass any stable identifier from your system (CRM id, phone, email…) as\n`external_id`. It is stored on the issued card and echoed back in every related\n**webhook**, so you can correlate events with your own records. Optionally tag\nthe source via `external_source` (e.g. `hubspot`, `shopify`).\n\nIf your profile has exactly **one** active card template, `template_id` may be\nomitted everywhere — it is selected automatically. With multiple templates,\n`template_id` is required.\n\n## Endpoints\n- **Cards** — create invites (always a fresh code), look up and inspect cards.\n- **Templates** — list templates and read a template's design.\n- **Vouchers** — issue a voucher straight to a card.\n- **Messages** — message a card owner over the email or wallet card.\n\n## Webhooks\nConfigure a webhook URL for your profile to receive card events. Every event uses\none payload shape and differs only by `event_type`. See the **Webhooks** section\nat the very bottom of this page for the full schema, the list of event types and\nwhich fields apply to each.\n\n## Support\n- [Knowledge Base](https://7stamp.com/en/knowledge-base/)\n- [Contact Us](https://7stamp.com/en/contact/)","version":"1.0.0"},"servers":[{"url":"/cards-api"}],"paths":{"/cards/invite":{"post":{"tags":["Cards"],"summary":"Create Card Invite","description":"Create a card invite link for an external contact.\n\nA **new** delivery-insert code is always generated — even for a returning\ncontact — so \"blind\" external systems can repeatedly grant a card and its\nstamps. Send the returned `install_url` to the contact.\n\n- **template_id** optional: auto-selected when the profile has exactly one\n  active template; with multiple templates it is required.\n- **external_id**: stored on the card and included in webhooks.","operationId":"create_card_invite","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardInviteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardInviteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/cards/invite/bulk":{"post":{"tags":["Cards"],"summary":"Bulk Card Invite","description":"Create up to 100 card invites in one call.\n\nEach item is processed independently — a failure on one item does not stop\nthe others. Inspect the `error` field of each result to detect failures.","operationId":"bulk_card_invite","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCardInviteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCardInviteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/cards":{"get":{"tags":["Cards"],"summary":"Find Customer","description":"Find card(s) by external contact ID.\n\nReturns only cards belonging to the caller's profile.","operationId":"find_customer","parameters":[{"description":"External contact ID","required":true,"schema":{"type":"string","maxLength":255,"title":"External Id","description":"External contact ID"},"name":"external_id","in":"query"},{"description":"Your system name","required":false,"schema":{"type":"string","maxLength":100,"title":"External Source","description":"Your system name"},"name":"external_source","in":"query"},{"description":"Card template ID (optional filter)","required":false,"schema":{"type":"integer","title":"Template Id","description":"Card template ID (optional filter)"},"name":"template_id","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CustomerResponse"},"type":"array","title":"Response Find Customer Cards Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/cards/scan":{"post":{"tags":["Cards"],"summary":"Scan Card","description":"Scan a card identified by `external_id` (or `user_card_id`) and add stamps.\n\nSame scan pipeline as the POS scanner (rate limit, billing quota, stamps,\ngoals, lottery, webhooks) — only the card is addressed by your external\nidentifier instead of its QR code.\n\n- **stamps_count** takes priority over **amount**.\n- **external_order_id** is echoed back in the resulting webhooks.","operationId":"scan_card","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScannerScanResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/cards/{user_card_id}":{"get":{"tags":["Cards"],"summary":"Get Card Detail","description":"Get full card state by internal card ID.\n\nReturns stamps balance, wallet status, active vouchers count and external\nidentifiers. Only cards belonging to the caller's profile are accessible.","operationId":"get_card_detail","parameters":[{"description":"Internal card ID","required":true,"schema":{"type":"integer","title":"User Card Id","description":"Internal card ID"},"name":"user_card_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List Templates","description":"List active card templates of your profile.\n\nUse a template's `id` as `template_id` in other endpoints. If the profile has\nexactly one active template, `template_id` may be omitted everywhere.","operationId":"list_templates","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TemplateListItem"},"type":"array","title":"Response List Templates Templates Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/templates/{template_id}/design":{"get":{"tags":["Templates"],"summary":"Get Template Design","description":"Get the full card design for a template.\n\nReturns every design attribute (colors, logo, background, stamp visuals,\ntexts and their translations) so you can render or mirror the card's look.","operationId":"get_template_design","parameters":[{"description":"Card template ID","required":true,"schema":{"type":"integer","title":"Template Id","description":"Card template ID"},"name":"template_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardDesignResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/vouchers/issue":{"post":{"tags":["Vouchers"],"summary":"Issue Voucher","description":"Issue a voucher to a card identified by `external_id` (or `user_card_id`).\n\nThis is the same operation as the admin \"issue voucher to card\" — only the\ncard is addressed by your external identifier. The card owner receives the\nwallet push and bot/email notification, and a `VOUCHER_ISSUED`-style card\nevent webhook is emitted.","operationId":"issue_voucher","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueVoucherRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminIssueVoucherResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/messages/send":{"post":{"tags":["Messages"],"summary":"Send Message","description":"Send a message to a card owner identified by `external_id` (or `user_card_id`).\n\nCard holders sign in with Google/Apple, so they are reached via:\n- **CARD** — short push on the wallet card (`card_push_text`); always available.\n- **EMAIL** — `subject` + `body` to the owner's email; optional.\n\nRestrict delivery with `channels`, or omit it to send on every channel for\nwhich content is provided.","operationId":"send_message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}}},"webhooks":{"card-event":{"post":{"tags":["Webhooks"],"summary":"Card event (all types)","description":"Sent to your configured webhook URL on every card event.\n\nThe `event_type` field tells you what happened — one of:\n`SCAN`, `REWARD_EARNED`, `VOUCHER_ISSUED`, `VOUCHER_REDEEMED`, `LOTTERY_WIN`,\n`DELIVERY_INSERT`, `CARD_JOINED`, `CARD_CAMPAIGN`, `BIRTHDAY_GREETING`,\n`ADMIN_VOUCHER_ISSUE`, `CARD_ADDED_TO_WALLET`, `CARD_REMOVED_FROM_WALLET`.\n\nDelivery is signed with `X-Webhook-Signature` (HMAC-SHA256 over\n`timestamp + payload`). Respond `2xx` to acknowledge.","operationId":"card_eventcard_event_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCardEventDataSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AchievedGoalSchema":{"properties":{"stamp_number":{"type":"integer","title":"Stamp Number","description":"Stamp number where goal was achieved"},"name":{"type":"string","title":"Name","description":"Localized stamp name"},"greeting_text":{"type":"string","title":"Greeting Text","description":"Reward/greeting text"},"cycle_number":{"type":"integer","title":"Cycle Number","description":"Cycle number (1, 2, 3...)"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/ClientCardStampTranslationSchema"},"type":"object","title":"Translations","description":"Translations for name and greeting_text"},"source":{"allOf":[{"$ref":"#/components/schemas/RewardSourceEnum"}],"description":"Origin of this reward (GOAL, LOTTERY, ...); null for legacy rows"}},"type":"object","required":["stamp_number","greeting_text","cycle_number"],"title":"AchievedGoalSchema","description":"Single achieved goal from this scan"},"AdminIssueVoucherResponse":{"properties":{"id":{"type":"integer","title":"Id"},"unique_code":{"type":"string","title":"Unique Code"},"status":{"type":"string","title":"Status"},"stamp_number":{"type":"integer","title":"Stamp Number"},"issued_at":{"type":"string","format":"date-time","title":"Issued At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At","nullable":true},"voucher_template_id":{"type":"integer","title":"Voucher Template Id"},"user_card_id":{"type":"integer","title":"User Card Id","nullable":true},"image_url":{"type":"string","title":"Image Url","nullable":true},"short_description":{"type":"string","title":"Short Description","default":""}},"type":"object","required":["id","unique_code","status","stamp_number","issued_at","voucher_template_id"],"title":"AdminIssueVoucherResponse","description":"Response after issuing a voucher (standalone or to a user)"},"ApplePassStyleEnum":{"type":"string","enum":["generic","storeCard","eventTicket","coupon","boardingPass"],"title":"ApplePassStyleEnum","description":"Apple Wallet pass styles."},"BulkCardInviteRequest":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CardInviteRequest"},"type":"array","maxItems":100,"minItems":1,"title":"Items","description":"Invite requests (max 100). Items are processed independently."}},"type":"object","required":["items"],"title":"BulkCardInviteRequest","description":"Create up to 100 card invites in a single call."},"BulkCardInviteResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/CardInviteResponse"},"type":"array","title":"Results","description":"Results in the same order as the request items."},"success_count":{"type":"integer","title":"Success Count","description":"Number of successful items."},"error_count":{"type":"integer","title":"Error Count","description":"Number of failed items."}},"type":"object","required":["results","success_count","error_count"],"title":"BulkCardInviteResponse","description":"Per-item results for a bulk invite call."},"CardDesignResponse":{"properties":{"id":{"type":"integer","title":"Id"},"card_template_id":{"type":"integer","title":"Card Template Id"},"logo_url":{"type":"string","title":"Logo Url"},"background_color":{"type":"string","title":"Background Color"},"organization_name":{"type":"string","title":"Organization Name"},"barcode_message":{"type":"string","title":"Barcode Message"},"valid_from":{"type":"string","format":"date","title":"Valid From"},"valid_until":{"type":"string","format":"date","title":"Valid Until"},"expiration_date":{"type":"string","format":"date","title":"Expiration Date"},"palette_secondary_color":{"type":"string","title":"Palette Secondary Color"},"palette_background_image_url":{"type":"string","title":"Palette Background Image Url"},"palette_stamp_active_color":{"type":"string","title":"Palette Stamp Active Color"},"palette_stamp_inactive_color":{"type":"string","title":"Palette Stamp Inactive Color"},"palette_accent_color":{"type":"string","title":"Palette Accent Color"},"header_bg_color":{"type":"string","title":"Header Bg Color"},"header_bg_image":{"type":"string","title":"Header Bg Image"},"font":{"type":"string","title":"Font"},"stamp_block_bg_color":{"type":"string","title":"Stamp Block Bg Color"},"stamp_block_bg_image":{"type":"string","title":"Stamp Block Bg Image"},"header_text_content":{"type":"string","title":"Header Text Content"},"header_text_content_color":{"type":"string","title":"Header Text Content Color"},"page_bg_color":{"type":"string","title":"Page Bg Color"},"page_bg_image":{"type":"string","title":"Page Bg Image"},"pass_style":{"$ref":"#/components/schemas/ApplePassStyleEnum"},"grouping_identifier":{"type":"string","title":"Grouping Identifier"},"apple_strip_image_url":{"type":"string","title":"Apple Strip Image Url","description":"Apple Wallet strip image URL (non-stamp cards)","nullable":true},"card_type":{"$ref":"#/components/schemas/GoogleCardTypeEnum"},"generic_type":{"$ref":"#/components/schemas/GoogleGenericTypeEnum"},"wide_logo_url":{"type":"string","title":"Wide Logo Url"},"header_image_url":{"type":"string","title":"Header Image Url"},"image_width":{"type":"integer","title":"Image Width"},"image_height":{"type":"integer","title":"Image Height"},"stamps_per_row":{"type":"integer","title":"Stamps Per Row"},"stamp_size":{"type":"integer","title":"Stamp Size"},"stamp_spacing":{"type":"integer","title":"Stamp Spacing"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/CardDesignTranslationSchema"},"type":"object","title":"Translations","description":"Translations for different languages"},"time_created":{"type":"string","format":"date-time","title":"Time Created"},"time_updated":{"type":"string","format":"date-time","title":"Time Updated"}},"type":"object","required":["id","card_template_id","background_color","image_width","image_height","stamps_per_row","stamp_size","stamp_spacing","time_created","time_updated"],"title":"CardDesignResponse","description":"Schema for card design response"},"CardDesignTranslationSchema":{"properties":{"header_text_content":{"type":"string","title":"Header Text Content","nullable":true},"barcode_message":{"type":"string","title":"Barcode Message","nullable":true}},"type":"object","title":"CardDesignTranslationSchema","description":"Translation schema for card design fields"},"CardDetailResponse":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Internal card ID."},"card_template_id":{"type":"integer","title":"Card Template Id","description":"Card template ID."},"public_token":{"type":"string","title":"Public Token","description":"Public token (QR value)."},"stamps_count":{"type":"integer","title":"Stamps Count","description":"Current stamps balance."},"external_id":{"type":"string","title":"External Id","description":"External contact identifier.","nullable":true},"external_source":{"type":"string","title":"External Source","description":"Your system name.","nullable":true},"is_apple_wallet":{"type":"boolean","title":"Is Apple Wallet","description":"Pass added to Apple Wallet."},"is_google_wallet":{"type":"boolean","title":"Is Google Wallet","description":"Pass added to Google Wallet."},"apple_wallet_url":{"type":"string","title":"Apple Wallet Url","description":"Apple Wallet pass URL.","nullable":true},"google_pay_url":{"type":"string","title":"Google Pay Url","description":"Google Pay pass JWT.","nullable":true},"active_vouchers_count":{"type":"integer","title":"Active Vouchers Count","description":"Number of currently active vouchers."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Card creation timestamp.","nullable":true}},"type":"object","required":["user_card_id","card_template_id","public_token","stamps_count","is_apple_wallet","is_google_wallet","active_vouchers_count"],"title":"CardDetailResponse","description":"Full state of a single card."},"CardInviteRequest":{"properties":{"template_id":{"type":"integer","title":"Template Id","description":"Card template ID. If omitted and the profile has exactly one active template, that template is used automatically."},"external_id":{"type":"string","maxLength":255,"title":"External Id","description":"Your contact identifier (e.g. CRM id, phone, email)."},"external_source":{"type":"string","maxLength":100,"title":"External Source","description":"Your system name (e.g. 'hubspot', 'bitrix24', 'shopify')."},"stamps_count":{"type":"integer","minimum":0.0,"title":"Stamps Count","description":"Stamps to pre-grant on activation (quantity-based cards)."},"stamps_amount":{"type":"number","minimum":0.0,"title":"Stamps Amount","description":"Purchase amount to convert into stamps (amount-based cards)."}},"type":"object","required":["external_id"],"title":"CardInviteRequest","description":"Request to issue a loyalty card invite for an external contact.","example":{"external_id":"crm_contact_8821","external_source":"hubspot","stamps_count":2}},"CardInviteResponse":{"properties":{"install_url":{"type":"string","title":"Install Url","description":"Send this URL to the contact to install the card. A NEW invite is always generated, even for a returning contact."},"bot_url":{"type":"string","title":"Bot Url","description":"Same invite through the profile's bot instead of the web: t.me/<bot>?start=... for Telegram, wa.me/<phone>?text=... for WhatsApp. Null when the profile has no bot connected.","nullable":true},"delivery_insert_code":{"type":"string","title":"Delivery Insert Code","description":"Newly generated delivery-insert code (UUID)."},"external_id":{"type":"string","title":"External Id","description":"Echoed external contact identifier."},"template_id":{"type":"integer","title":"Template Id","description":"Card template the invite was created for."},"error":{"type":"string","title":"Error","description":"Per-item error message (only populated inside bulk responses)."}},"type":"object","required":["install_url","delivery_insert_code","external_id","template_id"],"title":"CardInviteResponse","description":"Result of a card invite — always a fresh delivery-insert code.","example":{"install_url":"https://my.7stamp.com/42?delivery_insert_code=8c1f...e9","delivery_insert_code":"8c1f0b3a-1d2e-4a5b-9c7d-0f1e2d3c4b5a","external_id":"crm_contact_8821","template_id":42}},"ClientCardDesignSchema":{"properties":{"logo_url":{"type":"string","title":"Logo Url"},"profile_image_url":{"type":"string","title":"Profile Image Url","description":"Brand profile image URL"},"profile_name":{"type":"string","title":"Profile Name","description":"Profile name (Group.name)"},"background_color":{"type":"string","title":"Background Color"},"foreground_color":{"type":"string","title":"Foreground Color"},"header_bg_color":{"type":"string","title":"Header Bg Color"},"header_bg_image":{"type":"string","title":"Header Bg Image"},"font":{"type":"string","title":"Font"},"header_text_content":{"type":"string","title":"Header Text Content"},"header_text_content_color":{"type":"string","title":"Header Text Content Color"},"stamp_block_bg_color":{"type":"string","title":"Stamp Block Bg Color"},"stamp_block_bg_image":{"type":"string","title":"Stamp Block Bg Image"},"page_bg_color":{"type":"string","title":"Page Bg Color"},"page_bg_image":{"type":"string","title":"Page Bg Image"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/ClientCardDesignTranslationSchema"},"type":"object","title":"Translations","description":"Translations for design fields"}},"type":"object","title":"ClientCardDesignSchema","description":"Card design for client"},"ClientCardDesignTranslationSchema":{"properties":{"header_text_content":{"type":"string","title":"Header Text Content"},"barcode_message":{"type":"string","title":"Barcode Message"}},"type":"object","title":"ClientCardDesignTranslationSchema","description":"Translations for CardDesign"},"ClientCardStampTranslationSchema":{"properties":{"name":{"type":"string","title":"Name"},"greeting_text":{"type":"string","title":"Greeting Text"},"short_description":{"type":"string","title":"Short Description"},"long_description":{"type":"string","title":"Long Description"},"lottery_name":{"type":"string","title":"Lottery Name"}},"type":"object","title":"ClientCardStampTranslationSchema","description":"Translations for CardStamp / Goal"},"ClientCardTemplateTranslationSchema":{"properties":{"birthday_greeting":{"type":"string","title":"Birthday Greeting"}},"type":"object","title":"ClientCardTemplateTranslationSchema","description":"Translations for CardTemplate"},"ClientRegularStampSchema":{"properties":{"active_stamp_image_url":{"type":"string","title":"Active Stamp Image Url"},"inactive_stamp_image_url":{"type":"string","title":"Inactive Stamp Image Url"},"active_stamp_bg_color":{"type":"string","title":"Active Stamp Bg Color"},"inactive_stamp_bg_color":{"type":"string","title":"Inactive Stamp Bg Color"},"active_stamp_border_color":{"type":"string","title":"Active Stamp Border Color"},"inactive_stamp_border_color":{"type":"string","title":"Inactive Stamp Border Color"}},"type":"object","title":"ClientRegularStampSchema","description":"Regular stamp appearance"},"CustomerResponse":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Internal card ID."},"card_template_id":{"type":"integer","title":"Card Template Id","description":"Card template ID."},"public_token":{"type":"string","title":"Public Token","description":"Public token (QR value)."},"stamps_count":{"type":"integer","title":"Stamps Count","description":"Current stamps balance."},"external_id":{"type":"string","title":"External Id","description":"External contact identifier."},"external_source":{"type":"string","title":"External Source","description":"Your system name."}},"type":"object","required":["user_card_id","card_template_id","public_token","stamps_count","external_id"],"title":"CustomerResponse","description":"A card matched by external contact identifier."},"GoogleCardTypeEnum":{"type":"string","enum":["loyalty","generic"],"title":"GoogleCardTypeEnum","description":"Google Wallet card types."},"GoogleGenericTypeEnum":{"type":"string","enum":["GENERIC_TYPE_UNSPECIFIED","GENERIC_GYM_MEMBERSHIP","GENERIC_VOUCHER","GENERIC_SEASON_PASS","GENERIC_UTILITY_BILLS","GENERIC_PARKING_PASS","GENERIC_LIBRARY_MEMBERSHIP","GENERIC_RESERVATIONS","GENERIC_AUTO_INSURANCE","GENERIC_HOME_INSURANCE","GENERIC_ENTRY_TICKET","GENERIC_RECEIPT","GENERIC_OTHER"],"title":"GoogleGenericTypeEnum","description":"Google Wallet generic pass types (ONLY for card_type=GENERIC, not for LOYALTY)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IssueVoucherRequest":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Target card ID. Takes priority over external_id when set."},"external_id":{"type":"string","maxLength":255,"title":"External Id","description":"External contact identifier (used when user_card_id is omitted)."},"external_source":{"type":"string","maxLength":100,"title":"External Source","description":"Your system name (optional disambiguation)."},"template_id":{"type":"integer","title":"Template Id","description":"Card template ID. If omitted and the profile has exactly one active template, that template is used automatically."},"voucher":{"allOf":[{"$ref":"#/components/schemas/VoucherTemplateNestedCreate"}],"title":"Voucher","description":"Voucher template data."}},"type":"object","required":["voucher"],"title":"IssueVoucherRequest","description":"Issue a voucher to a card identified by external_id or user_card_id.","example":{"external_id":"crm_contact_8821","external_source":"hubspot","voucher":{"short_description":"Free coffee","validity_type":"DAYS","validity_value":30}}},"IssuedVoucherResponse":{"properties":{"id":{"type":"integer","title":"Id"},"unique_code":{"type":"string","title":"Unique Code","description":"12-character unique redemption code"},"status":{"allOf":[{"$ref":"#/components/schemas/IssuedVoucherStatusEnum"}],"description":"Voucher status: active, redeemed, expired"},"stamp_number":{"type":"integer","title":"Stamp Number","description":"Goal step number when voucher was issued"},"source":{"allOf":[{"$ref":"#/components/schemas/RewardSourceEnum"}],"description":"Origin of this voucher (GOAL, LOTTERY, ADMIN_MANUAL, ...); null for legacy rows"},"issued_at":{"type":"string","format":"date-time","title":"Issued At","description":"When voucher was issued"},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When voucher expires"},"redeemed_at":{"type":"string","format":"date-time","title":"Redeemed At","description":"When voucher was used"},"short_description":{"type":"string","title":"Short Description","description":"Short voucher description"},"long_description":{"type":"string","title":"Long Description","description":"Detailed description"},"image_url":{"type":"string","title":"Image Url","description":"Voucher image URL"},"voucher_type":{"allOf":[{"$ref":"#/components/schemas/VoucherTypeEnum"}],"description":"Voucher type"},"external_code":{"type":"string","title":"External Code","description":"External promo code for POS"},"translations":{"additionalProperties":{"additionalProperties":{"type":"string"},"type":"object"},"type":"object","title":"Translations","description":"Translations for voucher fields"}},"type":"object","required":["id","unique_code","status","stamp_number","issued_at","short_description","voucher_type"],"title":"IssuedVoucherResponse","description":"Response schema for issued voucher (shown after scan or in list)"},"IssuedVoucherStatusEnum":{"type":"string","enum":["ACTIVE","REDEEMED","EXPIRED"],"title":"IssuedVoucherStatusEnum","description":"Issued voucher status enumeration.\n\nACTIVE - voucher can be used\nREDEEMED - voucher was used\nEXPIRED - voucher expired without being used"},"LotteryConfig":{"properties":{"variants":{"items":{"$ref":"#/components/schemas/LotteryVariant"},"type":"array","minItems":1,"title":"Variants","description":"Lottery variants"},"name":{"type":"string","maxLength":255,"title":"Name","description":"Lottery wheel name"},"name_translations":{"additionalProperties":{"type":"string"},"type":"object","title":"Name Translations","description":"Translations for lottery wheel name"}},"type":"object","required":["variants"],"title":"LotteryConfig","description":"Full lottery configuration stored in CardStamp.lottery_config — internal/DB format."},"LotteryGoalResultSchema":{"properties":{"stamp_number":{"type":"integer","title":"Stamp Number","description":"Goal stamp number that triggered lottery"},"cycle_number":{"type":"integer","title":"Cycle Number","description":"Card cycle number when this lottery was triggered","default":1},"spins_count":{"type":"integer","title":"Spins Count","description":"Total spins (>1 if spin_again triggered)"},"final_type":{"allOf":[{"$ref":"#/components/schemas/LotteryVariantTypeEnum"}],"description":"Final result type (never spin_again)"},"name":{"type":"string","title":"Name","description":"Winner variant name"},"greeting_text":{"type":"string","title":"Greeting Text","description":"Winner reward text"},"image_url":{"type":"string","title":"Image Url","description":"Winner reward image URL"},"issued_voucher_id":{"type":"integer","title":"Issued Voucher Id","description":"Issued voucher ID if final result is voucher"},"spins":{"items":{"$ref":"#/components/schemas/LotterySpinSchema"},"type":"array","title":"Spins","description":"All spin details for animation"},"awards_issued":{"type":"boolean","title":"Awards Issued","description":"True if reward/voucher was issued immediately; False if pending confirmation","default":false},"lottery_name":{"type":"string","title":"Lottery Name","description":"Lottery wheel name from LotteryConfig.name"},"lottery_name_translations":{"additionalProperties":{"type":"string"},"type":"object","title":"Lottery Name Translations","description":"Translations for lottery wheel name"}},"type":"object","required":["stamp_number","spins_count","final_type"],"title":"LotteryGoalResultSchema","description":"Full lottery result for a single goal (all spins combined)."},"LotterySpinSchema":{"properties":{"spin_number":{"type":"integer","title":"Spin Number","description":"Spin number (1, 2, 3... if spin_again)"},"result_type":{"allOf":[{"$ref":"#/components/schemas/LotteryVariantTypeEnum"}],"description":"Result type of this spin"},"variant_index":{"type":"integer","title":"Variant Index","description":"Index of chosen variant in lottery_config.variants array. Null if forced no_win by spin_again limit."},"name":{"type":"string","title":"Name","description":"Variant name at time of spin"},"greeting_text":{"type":"string","title":"Greeting Text","description":"Reward text at time of spin"},"image_url":{"type":"string","title":"Image Url","description":"Reward image URL at time of spin"},"issued_voucher_id":{"type":"integer","title":"Issued Voucher Id","description":"Issued voucher ID if voucher won"}},"type":"object","required":["spin_number","result_type"],"title":"LotterySpinSchema","description":"Single spin result (for animation/history)."},"LotteryVariant":{"properties":{"type":{"allOf":[{"$ref":"#/components/schemas/LotteryVariantTypeEnum"}],"description":"Variant type"},"probability":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Probability","description":"Probability percent (0-100)"},"name":{"type":"string","maxLength":255,"title":"Name","description":"Variant display name"},"greeting_text":{"type":"string","maxLength":512,"title":"Greeting Text","description":"Reward text shown to user"},"image_url":{"type":"string","maxLength":512,"title":"Image Url","description":"Reward image URL (for reward type)"},"voucher_template_id":{"type":"integer","title":"Voucher Template Id","description":"Voucher template ID (for voucher type)"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/LotteryVariantTranslationSchema"},"type":"object","title":"Translations","description":"Translations for variant text fields"}},"type":"object","required":["type","probability"],"title":"LotteryVariant","description":"Single variant in lottery config — internal/DB format (uses voucher_template_id)."},"LotteryVariantTranslationSchema":{"properties":{"name":{"type":"string","title":"Name","nullable":true},"greeting_text":{"type":"string","title":"Greeting Text","nullable":true}},"type":"object","title":"LotteryVariantTranslationSchema","description":"Translation schema for lottery variant fields"},"LotteryVariantTypeEnum":{"type":"string","enum":["reward","voucher","spin_again","no_win"],"title":"LotteryVariantTypeEnum","description":"Lottery variant result types."},"MessageChannel":{"type":"string","enum":["CARD","EMAIL"],"title":"MessageChannel","description":"Channels a card message can be sent over."},"ReceiptData":{"properties":{"receipt_id":{"type":"string","maxLength":255,"title":"Receipt Id","description":"Receipt ID in the source system."},"total":{"type":"number","minimum":0.0,"title":"Total","description":"Receipt total amount."},"currency":{"type":"string","maxLength":10,"title":"Currency","description":"Currency code."},"items":{"items":{"$ref":"#/components/schemas/ReceiptItem"},"type":"array","title":"Items","description":"Receipt line items."}},"type":"object","title":"ReceiptData","description":"Structured receipt accepted by the scan endpoints.\n\nOptional everywhere. When provided in the canonical format we store it and,\nfor By-item cards, derive stamps from the line items. Existing integrations\nthat don't send it keep working unchanged (only ``external_order_id``).","example":{"receipt_id":"R-100500","total":"50.00","currency":"UAH","items":[{"code":"SKU-101","name":"Latte","price":"25.00","quantity":2},{"code":"4820000123","name":"Cake","price":"30.00","quantity":1}]}},"ReceiptItem":{"properties":{"code":{"type":"string","maxLength":255,"title":"Code","description":"Product code / SKU. Matched (case-insensitive) against the card template's configured item codes for By-item cards."},"name":{"type":"string","maxLength":512,"title":"Name","description":"Product name (optional)."},"price":{"type":"number","minimum":0.0,"title":"Price","description":"Unit price (optional)."},"quantity":{"type":"number","minimum":0.0,"title":"Quantity","description":"Quantity of this item. For By-item cards each matched unit earns one stamp (code A x2 + code B x1 → 3 stamps).","default":1}},"type":"object","required":["code"],"title":"ReceiptItem","description":"A single line item of a receipt.\n\n``code`` is the product code / SKU used for the By-item stamp mode: a stamp\nis earned for every unit of a product whose code is configured on the card\ntemplate (``item_codes``)."},"RewardSourceEnum":{"type":"string","enum":["GOAL","LOTTERY","ADMIN_MANUAL","ADMIN_STANDALONE","CAMPAIGN","BIRTHDAY","MARKETING_AUTOMATION"],"title":"RewardSourceEnum","description":"Origin of an issued voucher or achieved goal reward.\n\nGOAL - regular card stamp goal (incl. delivery insert - same mechanism)\nLOTTERY - lottery wheel spin win\nADMIN_MANUAL - admin issued manually to a specific card\nADMIN_STANDALONE - admin issued a voucher not tied to any card\nCAMPAIGN - card campaign / mailing\nBIRTHDAY - birthday greeting voucher\nMARKETING_AUTOMATION - marketing automation rule"},"ScanRequest":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Target card ID. Takes priority over external_id when set."},"external_id":{"type":"string","maxLength":255,"title":"External Id","description":"External contact identifier (used when user_card_id is omitted)."},"external_source":{"type":"string","maxLength":100,"title":"External Source","description":"Your system name (optional disambiguation)."},"template_id":{"type":"integer","title":"Template Id","description":"Card template ID. If omitted and the profile has exactly one active template, that template is used automatically."},"amount":{"type":"number","minimum":0.0,"title":"Amount","description":"Purchase amount (amount-based cards)."},"stamps_count":{"type":"integer","minimum":0.0,"title":"Stamps Count","description":"Explicit number of stamps to add (takes priority over amount)."},"lottery_immediate":{"type":"boolean","title":"Lottery Immediate","description":"Issue lottery awards immediately instead of deferring to confirmation.","default":false},"external_order_id":{"type":"string","maxLength":255,"title":"External Order Id","description":"Your order/transaction ID (echoed in webhooks)."},"receipt":{"allOf":[{"$ref":"#/components/schemas/ReceiptData"}],"title":"Receipt","description":"Structured receipt with line items. Required for By-item cards (stamps are derived from matching product codes); stored for audit.","nullable":true}},"type":"object","title":"ScanRequest","description":"Scan a card identified by external_id (or user_card_id) and add stamps.","example":{"external_id":"crm_contact_8821","external_order_id":"order_55012","receipt":{"receipt_id":"R-100500","items":[{"code":"SKU-101","quantity":2},{"code":"4820000123","quantity":1}]}}},"ScannerCardTemplateSchema":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"stamp_price":{"type":"number","title":"Stamp Price","description":"Price per one stamp for amount-based cards"},"is_apple":{"type":"boolean","title":"Is Apple","description":"Apple Wallet support"},"is_google":{"type":"boolean","title":"Is Google","description":"Google Wallet support"},"ask_user_birthday":{"type":"boolean","title":"Ask User Birthday","description":"Whether to ask user for birthday"},"birthday_reminder_days":{"type":"integer","title":"Birthday Reminder Days","description":"Days before birthday to send reminder"},"stamps_count":{"type":"integer","title":"Stamps Count","description":"Current stamps collected"},"max_stamps":{"type":"integer","title":"Max Stamps","description":"Maximum stamps (final goal)"},"current_apple_wallet_image_url":{"type":"string","title":"Current Apple Wallet Image Url","description":"Apple Wallet image for current stamp step"},"current_google_wallet_image_url":{"type":"string","title":"Current Google Wallet Image Url","description":"Google Wallet image for current stamp step"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/ClientCardTemplateTranslationSchema"},"type":"object","title":"Translations","description":"Translations for template fields"}},"type":"object","required":["id","name","is_apple","is_google","ask_user_birthday","stamps_count","max_stamps"],"title":"ScannerCardTemplateSchema","description":"Card template info for scanner (includes stamps state)"},"ScannerGoalStampSchema":{"properties":{"stamp_number":{"type":"integer","title":"Stamp Number","description":"Stamp number to reach this goal"},"name":{"type":"string","title":"Name","description":"Goal name (translated)"},"greeting_text":{"type":"string","title":"Greeting Text","description":"Reward text for Award (translated)"},"greeting_text_color":{"type":"string","title":"Greeting Text Color","description":"Greeting text color"},"image_url":{"type":"string","title":"Image Url","description":"Goal/voucher image URL"},"voucher_template_id":{"type":"integer","title":"Voucher Template Id","description":"Voucher template ID if goal issues voucher, null for text award"},"short_description":{"type":"string","title":"Short Description","description":"Voucher short description (translated)"},"long_description":{"type":"string","title":"Long Description","description":"Voucher long description (translated)"},"voucher":{"allOf":[{"$ref":"#/components/schemas/VoucherTemplateResponse"}],"title":"Voucher","description":"Voucher template if goal issues voucher"},"active_stamp_image_url":{"type":"string","title":"Active Stamp Image Url","description":"Image when stamp is active/collected"},"inactive_stamp_image_url":{"type":"string","title":"Inactive Stamp Image Url","description":"Image when stamp is not yet collected"},"active_stamp_bg_color":{"type":"string","title":"Active Stamp Bg Color","description":"Background color for active stamp"},"inactive_stamp_bg_color":{"type":"string","title":"Inactive Stamp Bg Color","description":"Background color for inactive stamp"},"active_stamp_border_color":{"type":"string","title":"Active Stamp Border Color","description":"Border color for active stamp"},"inactive_stamp_border_color":{"type":"string","title":"Inactive Stamp Border Color","description":"Border color for inactive stamp"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/ClientCardStampTranslationSchema"},"type":"object","title":"Translations","description":"Translations for goal and voucher fields"},"lottery_config":{"allOf":[{"$ref":"#/components/schemas/LotteryConfig"}],"title":"Lottery Config","description":"Lottery (wheel of fortune) config if goal has lottery"}},"type":"object","required":["stamp_number"],"title":"ScannerGoalStampSchema","description":"Goal stamp with design for scanner (no is_achieved)"},"ScannerScanResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Scan success status"},"message":{"type":"string","title":"Message","description":"Human-readable message"},"scan_id":{"type":"integer","title":"Scan Id","description":"ID of created UserCardScan (use for /lottery/confirm)"},"stamps_added":{"type":"integer","title":"Stamps Added","description":"Number of stamps added (can be negative)"},"achieved_goals":{"items":{"$ref":"#/components/schemas/AchievedGoalSchema"},"type":"array","title":"Achieved Goals","description":"Goals achieved from THIS scan (including multiple cycles)"},"cycles_completed":{"type":"integer","title":"Cycles Completed","description":"Number of full cycles completed","default":0},"next_scan_allowed_at":{"type":"string","format":"date-time","title":"Next Scan Allowed At","description":"When next scan is allowed"},"invoice_id":{"type":"integer","title":"Invoice Id","description":"Created invoice ID"},"amount_paid":{"type":"number","title":"Amount Paid","description":"Amount paid in currency"},"issued_vouchers":{"items":{"$ref":"#/components/schemas/IssuedVoucherResponse"},"type":"array","title":"Issued Vouchers","description":"Vouchers issued in THIS scan (for achieved goals with voucher templates)"},"active_vouchers":{"items":{"$ref":"#/components/schemas/IssuedVoucherResponse"},"type":"array","title":"Active Vouchers","description":"All active (not redeemed/expired) vouchers for this user card"},"lottery_results":{"items":{"$ref":"#/components/schemas/LotteryGoalResultSchema"},"type":"array","title":"Lottery Results","description":"Lottery (wheel of fortune) results for goals with lottery_config"},"lottery_spins_count":{"type":"integer","title":"Lottery Spins Count","description":"Total wheel spins across all lottery goals in this scan (>1 if spin_again triggered)","default":0},"is_delivery_insert":{"type":"boolean","title":"Is Delivery Insert","description":"True if this scan resulted from a delivery insert code activation","default":false},"delivery_insert_code":{"type":"string","title":"Delivery Insert Code","description":"The delivery insert code that was activated (set only when is_delivery_insert=True)","nullable":true},"template":{"allOf":[{"$ref":"#/components/schemas/ScannerCardTemplateSchema"}],"title":"Template","description":"Card template info with stamps state"},"design":{"allOf":[{"$ref":"#/components/schemas/ClientCardDesignSchema"}],"title":"Design","description":"Card design for display"},"stamps":{"allOf":[{"$ref":"#/components/schemas/ScannerStampsSchema"}],"title":"Stamps","description":"Stamps with design"}},"type":"object","required":["success","message","scan_id","stamps_added","template","design","stamps"],"title":"ScannerScanResponse","description":"Scanner scan card response"},"ScannerStampsSchema":{"properties":{"regular":{"allOf":[{"$ref":"#/components/schemas/ClientRegularStampSchema"}],"title":"Regular","description":"Regular stamp design"},"goals":{"items":{"$ref":"#/components/schemas/ScannerGoalStampSchema"},"type":"array","title":"Goals","description":"Goal stamps with design"}},"type":"object","required":["goals"],"title":"ScannerStampsSchema","description":"Stamps configuration for scanner"},"SendMessageRequest":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Target card ID. Takes priority over external_id when set."},"external_id":{"type":"string","maxLength":255,"title":"External Id","description":"External contact identifier (used when user_card_id is omitted)."},"external_source":{"type":"string","maxLength":100,"title":"External Source","description":"Your system name (optional disambiguation)."},"template_id":{"type":"integer","title":"Template Id","description":"Card template ID. If omitted and the profile has exactly one active template, that template is used automatically."},"channels":{"items":{"$ref":"#/components/schemas/MessageChannel"},"type":"array","description":"Channels to send on (CARD and/or EMAIL). If omitted, inferred from the provided content."},"card_push_text":{"type":"string","maxLength":20,"title":"Card Push Text","description":"CARD channel: short text shown as a push on the wallet card (Apple/Google). Max 20 chars. Requires an installed pass."},"subject":{"type":"string","maxLength":255,"title":"Subject","description":"EMAIL channel: email subject."},"body":{"type":"string","maxLength":10000,"title":"Body","description":"EMAIL channel: email body (basic HTML allowed)."}},"type":"object","title":"SendMessageRequest","description":"Send a message to a card owner identified by external_id or user_card_id.\n\nCard holders sign in with Google/Apple, so they have an email but usually no\nmessenger. Two channels are available:\n- **CARD** — a short push on the wallet card (`card_push_text`). Always\n  available (cannot be turned off); requires an installed pass.\n- **EMAIL** — `subject` + `body` to the owner's email (optional).\n\nProvide the content for the channel(s) you want. Optionally restrict delivery\nwith `channels`; if omitted, channels are inferred from the content provided.","example":{"external_id":"crm_contact_8821","card_push_text":"Order ready!","subject":"Your order is ready","body":"Hi! Your order is ready for pickup. See you soon."}},"SendMessageResponse":{"properties":{"user_card_id":{"type":"integer","title":"User Card Id","description":"Resolved card ID."},"card_push_delivered":{"type":"boolean","title":"Card Push Delivered","description":"True if the wallet card push was queued for delivery.","default":false},"email_delivered":{"type":"boolean","title":"Email Delivered","description":"True if the email was queued for delivery.","default":false}},"type":"object","required":["user_card_id"],"title":"SendMessageResponse","description":"Result of a send-message call (per channel)."},"TemplateListItem":{"properties":{"id":{"type":"integer","title":"Id","description":"Card template ID (use as template_id)."},"name":{"type":"string","title":"Name","description":"Template name."},"description":{"type":"string","title":"Description","description":"Template description.","nullable":true},"max_stamps":{"type":"integer","title":"Max Stamps","description":"Total stamps on the card."},"stamp_price":{"type":"number","title":"Stamp Price","description":"Price per stamp. Set → amount-based card; null → quantity-based.","nullable":true},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the template is active."}},"type":"object","required":["id","name","max_stamps","is_active"],"title":"TemplateListItem","description":"A card template available in the profile."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ValidityTypeEnum":{"type":"string","enum":["UNLIMITED","DAYS","MONTHS","FIXED_DATE"],"title":"ValidityTypeEnum","description":"Voucher validity type enumeration.\n\nUNLIMITED - never expires\nDAYS - expires after N days from issue date\nMONTHS - expires after N months from issue date\nFIXED_DATE - expires on specific date regardless of issue date"},"VoucherTemplateNestedCreate":{"properties":{"short_description":{"type":"string","maxLength":255,"title":"Short Description","description":"Short voucher description"},"long_description":{"type":"string","maxLength":2048,"title":"Long Description","description":"Detailed description with terms and conditions"},"image_url":{"type":"string","maxLength":512,"title":"Image Url","description":"Voucher image URL"},"validity_type":{"allOf":[{"$ref":"#/components/schemas/ValidityTypeEnum"}],"description":"Validity type: DAYS, MONTHS, or FIXED_DATE","default":"DAYS"},"validity_value":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Validity Value","description":"Number of days/months for validity"},"validity_fixed_date":{"type":"string","format":"date","title":"Validity Fixed Date","description":"Fixed expiration date (for FIXED_DATE type)"},"voucher_type":{"allOf":[{"$ref":"#/components/schemas/VoucherTypeEnum"}],"description":"Voucher type (currently only GIFT is supported)","default":"GIFT"},"external_code":{"type":"string","maxLength":100,"title":"External Code","description":"External promo code for POS integration"},"is_active":{"type":"boolean","title":"Is Active","description":"Is voucher template active","default":true},"translations":{"additionalProperties":{"$ref":"#/components/schemas/VoucherTemplateTranslationSchema"},"type":"object","title":"Translations","description":"Translations for different languages"}},"type":"object","required":["short_description"],"title":"VoucherTemplateNestedCreate","description":"Nested voucher schema for CardStamp create.\nDoes NOT include profile_id - it's inherited from stamp's template."},"VoucherTemplateResponse":{"properties":{"id":{"type":"integer","title":"Id"},"profile_id":{"type":"integer","title":"Profile Id"},"short_description":{"type":"string","title":"Short Description"},"long_description":{"type":"string","title":"Long Description"},"image_url":{"type":"string","title":"Image Url"},"validity_type":{"$ref":"#/components/schemas/ValidityTypeEnum"},"validity_value":{"type":"integer","title":"Validity Value"},"validity_fixed_date":{"type":"string","format":"date","title":"Validity Fixed Date"},"voucher_type":{"$ref":"#/components/schemas/VoucherTypeEnum"},"external_code":{"type":"string","title":"External Code"},"is_active":{"type":"boolean","title":"Is Active"},"time_created":{"type":"string","format":"date-time","title":"Time Created"},"time_updated":{"type":"string","format":"date-time","title":"Time Updated"},"translations":{"additionalProperties":{"$ref":"#/components/schemas/VoucherTemplateTranslationSchema"},"type":"object","title":"Translations","description":"Translations for different languages"}},"type":"object","required":["id","profile_id","short_description","validity_type","voucher_type","is_active","time_created","time_updated"],"title":"VoucherTemplateResponse","description":"Schema for voucher template response"},"VoucherTemplateTranslationSchema":{"properties":{"short_description":{"type":"string","title":"Short Description","nullable":true},"long_description":{"type":"string","title":"Long Description","nullable":true}},"type":"object","title":"VoucherTemplateTranslationSchema","description":"Translation schema for voucher template fields"},"VoucherTypeEnum":{"type":"string","enum":["GIFT","CHECK_MODIFIER","CERTIFICATE"],"title":"VoucherTypeEnum","description":"Voucher type enumeration.\n\nGIFT - general gift voucher (currently the only supported type)\nCHECK_MODIFIER - modifies order total (discount) - reserved for future use\nCERTIFICATE - gift certificate (monetary value) - reserved for future use"},"WebhookCardEventAchievedGoalSchema":{"properties":{"stamp_number":{"type":"integer","title":"Stamp Number"},"name":{"type":"string","title":"Name","nullable":true},"greeting_text":{"type":"string","title":"Greeting Text","nullable":true},"cycle_number":{"type":"integer","title":"Cycle Number"}},"type":"object","required":["stamp_number","cycle_number"],"title":"WebhookCardEventAchievedGoalSchema"},"WebhookCardEventDataSchema":{"properties":{"event_type":{"type":"string","title":"Event Type","description":"Event type. One of: SCAN, REWARD_EARNED, VOUCHER_ISSUED, LOTTERY_WIN, VOUCHER_REDEEMED, DELIVERY_INSERT, CARD_JOINED, CARD_CAMPAIGN, BIRTHDAY_GREETING, ADMIN_VOUCHER_ISSUE, CARD_ADDED_TO_WALLET, CARD_REMOVED_FROM_WALLET. LOTTERY_WIN means a goal's lottery wheel awarded a prize — the prize is in achieved_goals (reward) or issued_vouchers (voucher)."},"scanned_at":{"type":"string","format":"date-time","title":"Scanned At","description":"When the event occurred."},"user_card_id":{"type":"integer","title":"User Card Id","description":"Internal card ID."},"card_template_id":{"type":"integer","title":"Card Template Id","description":"Card template ID."},"card_template_name":{"type":"string","title":"Card Template Name","description":"Card template name.","nullable":true},"stamps_added":{"type":"integer","title":"Stamps Added","description":"Stamps added (scan / delivery-insert).","default":0},"stamps_before":{"type":"integer","title":"Stamps Before","description":"Stamps before the event.","default":0},"stamps_after":{"type":"integer","title":"Stamps After","description":"Stamps after the event.","default":0},"amount":{"type":"integer","title":"Amount","description":"Purchase amount, if provided.","nullable":true},"external_order_id":{"type":"string","title":"External Order Id","description":"Your order/transaction ID.","nullable":true},"device_type":{"type":"string","title":"Device Type","description":"Wallet type (APPLE / GOOGLE) — set for CARD_ADDED_TO_WALLET / CARD_REMOVED_FROM_WALLET.","nullable":true},"external_id":{"type":"string","title":"External Id","description":"Your external contact identifier.","nullable":true},"external_source":{"type":"string","title":"External Source","description":"Your system name.","nullable":true},"issued_vouchers":{"items":{"$ref":"#/components/schemas/WebhookIssuedVoucherSchema"},"type":"array","title":"Issued Vouchers","description":"Vouchers issued by this event (VOUCHER_ISSUED / scan with reward).","default":[]},"achieved_goals":{"items":{"$ref":"#/components/schemas/WebhookCardEventAchievedGoalSchema"},"type":"array","title":"Achieved Goals","description":"Goals reached by this event (REWARD_EARNED / scan).","default":[]},"user":{"allOf":[{"$ref":"#/components/schemas/WebhookCardEventUser"}],"title":"User","description":"Card owner.","nullable":true}},"type":"object","required":["event_type","scanned_at","user_card_id","card_template_id"],"title":"WebhookCardEventDataSchema"},"WebhookCardEventUser":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name","description":"Display name.","nullable":true},"full_name":{"type":"string","title":"Full Name","description":"Full name.","nullable":true},"email":{"type":"string","title":"Email","description":"Email address.","nullable":true},"telegram_chat_id":{"type":"integer","title":"Telegram Chat Id","description":"Telegram chat ID.","nullable":true},"telegram_username":{"type":"string","title":"Telegram Username","description":"Telegram username.","nullable":true},"whatsapp_phone":{"type":"string","title":"Whatsapp Phone","description":"WhatsApp phone number.","nullable":true},"birth_date":{"type":"string","format":"date-time","title":"Birth Date","description":"Birth date.","nullable":true}},"type":"object","required":["id"],"title":"WebhookCardEventUser","description":"Card owner — essential contact fields only (card event webhooks)."},"WebhookIssuedVoucherSchema":{"properties":{"id":{"type":"integer","title":"Id"},"unique_code":{"type":"string","title":"Unique Code"},"stamp_number":{"type":"integer","title":"Stamp Number"},"issued_at":{"type":"string","format":"date-time","title":"Issued At","nullable":true},"expires_at":{"type":"string","format":"date-time","title":"Expires At","nullable":true},"status":{"type":"string","title":"Status"},"voucher_template_id":{"type":"integer","title":"Voucher Template Id","nullable":true},"voucher_description":{"type":"string","title":"Voucher Description","nullable":true},"voucher_image_url":{"type":"string","title":"Voucher Image Url","nullable":true}},"type":"object","required":["id","unique_code","stamp_number","status"],"title":"WebhookIssuedVoucherSchema"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}},"tags":[{"name":"Cards","description":"Create card invites and look up / inspect cards by external_id."},{"name":"Templates","description":"Read card template design by template_id."},{"name":"Vouchers","description":"Issue vouchers directly to a card identified by external_id."},{"name":"Messages","description":"Message a card owner over the wallet card push and/or email."}]}