import {z} from 'zod' export type CreateTicketAssignee = {id?: number | undefined}; export type LegacyChannelSlug = 'aircall' | 'api' | 'chat' | 'contact_form' | 'email' | 'facebook' | 'facebook-mention' | 'facebook-messenger' | 'facebook-recommendations' | 'help-center' | 'instagram-ad-comment' | 'instagram-comment' | 'instagram-direct-message' | 'instagram-mention' | 'internal-note' | 'phone' | 'sms' | 'twitter' | 'twitter-direct-message' | 'whatsapp' | 'yotpo-review'; export type CreateTicketCustomField = {id: number, value: unknown}; export type CreateTicketCustomer = {id?: number | undefined, email?: string | undefined, name?: string | undefined}; export type CreateTicketMessageAttachment = {url: string, name: string, size?: number | undefined, content_type: string, public?: boolean | undefined, extra?: (string | number | number | boolean | Record | Array) | undefined}; export type CreateTicketMessageLastSendingError = {error: string}; export type CreateTicketMessageMacro = {id: number}; export type CreateTicketMessageMeta = {relevant_content_indexes?: Array | undefined} | {[key: string]: unknown}; export type TicketMessageSourceType = 'aircall' | 'api' | 'app' | 'custom-chat' | 'chat' | 'chat-contact-form' | 'chat-offline-capture' | 'contact-form' | 'email' | 'facebook' | 'facebook-comment' | 'facebook-mention-comment' | 'facebook-mention-post' | 'facebook-message' | 'facebook-messenger' | 'facebook-post' | 'facebook-review' | 'facebook-review-comment' | 'form' | 'google-business-messages' | 'help-center' | 'help-center-contact-form' | 'helpdesk' | 'instagram' | 'instagram-ad-comment' | 'instagram-ad-media' | 'instagram-comment' | 'instagram-direct-message' | 'instagram-media' | 'instagram-mention-comment' | 'instagram-mention-media' | 'internal-note' | 'ottspott-call' | 'phone' | 'rule' | 'self_service' | 'shopify' | 'sms' | 'system-message' | 'tiktok-shop' | 'twilio' | 'twitter-direct-message' | 'twitter-mention-tweet' | 'twitter-quoted-tweet' | 'twitter-tweet' | 'whatsapp-message' | 'yotpo-review' | 'yotpo-review-private-comment' | 'yotpo-review-public-comment'; export type CreateTicketMessageSourcePerson = {name?: string | undefined, address?: string | undefined}; export type CreateTicketMessageSource = {type?: TicketMessageSourceType | undefined, from?: CreateTicketMessageSourcePerson | undefined, to?: Array | undefined, cc?: Array | undefined, bcc?: Array | undefined, extra?: (string | number | number | boolean | Record | Array) | undefined}; export type CreateTicketMessageCustomerChannel = {type: string, address: string}; export type CreateTicketMessageCustomerOrUser = {id?: number | undefined, email?: string | undefined, name?: string | undefined, external_id?: string | undefined, note?: string | undefined, timezone?: string | undefined, language?: string | undefined, meta?: Record | undefined, channels?: Array | undefined}; export type CreateTicketMessage = {actions?: (Array | Array>) | undefined, attachments?: Array | undefined, body_html?: string | undefined, body_text?: string | undefined, channel: LegacyChannelSlug | string, created_datetime?: string | undefined, deleted_datetime?: string | undefined, external_id?: string | undefined, failed_datetime?: string | undefined, from_agent: boolean, headers?: ({[key: string]: string | number | number | boolean | Record | Array}) | undefined, integration_id?: number | undefined, last_sending_error?: CreateTicketMessageLastSendingError | undefined, macros?: Array | undefined, message_id?: string | undefined, meta?: CreateTicketMessageMeta | undefined, opened_datetime?: string | undefined, public?: boolean | undefined, sent_datetime?: string | undefined, source?: CreateTicketMessageSource | undefined, stripped_html?: string | undefined, stripped_signature?: string | undefined, stripped_text?: string | undefined, subject?: string | undefined, via?: ('aircall' | 'api' | 'chat' | 'contact_form' | 'email' | 'facebook' | 'facebook-mention' | 'facebook-messenger' | 'facebook-recommendations' | 'form' | 'helpdesk' | 'help-center' | 'instagram' | 'instagram-ad-comment' | 'instagram-comment' | 'instagram-direct-message' | 'instagram-mention' | 'internal-note' | 'phone' | 'rule' | 'shopify' | 'sms' | 'twilio' | 'twitter' | 'twitter-direct-message' | 'whatsapp' | 'yotpo' | 'yotpo-review' | 'zendesk') | undefined, mention_ids?: Array | undefined, receiver?: CreateTicketMessageCustomerOrUser | undefined, sender?: CreateTicketMessageCustomerOrUser | undefined}; export type TicketPriority = 'critical' | 'high' | 'normal' | 'low'; export type TicketStatus = 'open' | 'closed'; export type CreateTicketTagDecoration = {color?: string | undefined}; export type CreateTicketTag = {name: string, decoration?: CreateTicketTagDecoration | undefined}; export type CreateTicket = {assignee_team?: CreateTicketAssignee | undefined, assignee_user?: CreateTicketAssignee | undefined, channel?: (LegacyChannelSlug | string) | undefined, closed_datetime?: string | undefined, created_datetime?: string | undefined, custom_fields?: Array | undefined, customer?: CreateTicketCustomer | undefined, external_id?: string | undefined, from_agent?: boolean | undefined, language?: string | undefined, last_message_datetime?: string | undefined, last_received_message_datetime?: string | undefined, messages: Array, meta?: ({[key: string]: string | number | number | boolean | Record | Array}) | undefined, opened_datetime?: string | undefined, priority?: TicketPriority | undefined, snooze_datetime?: string | undefined, spam?: boolean | undefined, split_from?: number | undefined, status?: TicketStatus | undefined, subject?: string | undefined, tags?: Array | undefined, trashed_datetime?: string | undefined, updated_datetime?: string | undefined, via?: ('aircall' | 'api' | 'chat' | 'contact_form' | 'email' | 'facebook' | 'facebook-mention' | 'facebook-messenger' | 'facebook-recommendations' | 'form' | 'helpdesk' | 'help-center' | 'instagram' | 'instagram-ad-comment' | 'instagram-comment' | 'instagram-direct-message' | 'instagram-mention' | 'internal-note' | 'phone' | 'rule' | 'shopify' | 'sms' | 'twilio' | 'twitter' | 'twitter-direct-message' | 'whatsapp' | 'yotpo' | 'yotpo-review' | 'zendesk') | undefined, imported?: boolean | undefined}; export type CreateApiApiTicketsArgs = {body: CreateTicket}; export type CreateApiApiTicketsOptions = {baseUrl?: string | undefined, basicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const ticketEventUser = z.object({id: z.number().int(), firstname: z.string(), lastname: z.string(), name: z.string(), email: z.string()}); export const ticketEvent = z.object({id: z.number().int(), type: z.string(), user: ticketEventUser, data: z.object({}), created_datetime: z.string()}); export const ticketStatus = z.enum(["open", "closed"]); export const legacyChannelSlug = z.enum(["aircall", "api", "chat", "contact_form", "email", "facebook", "facebook-mention", "facebook-messenger", "facebook-recommendations", "help-center", "instagram-ad-comment", "instagram-comment", "instagram-direct-message", "instagram-mention", "internal-note", "phone", "sms", "twitter", "twitter-direct-message", "whatsapp", "yotpo-review"]); export const ticketVia = z.enum(["aircall", "api", "chat", "contact_form", "email", "facebook", "facebook-mention", "facebook-messenger", "facebook-recommendations", "form", "gorgias_chat", "help-center", "helpdesk", "instagram", "instagram-ad-comment", "instagram-comment", "instagram-direct-message", "instagram-mention", "internal-note", "offline_capture", "phone", "rule", "self_service", "shopify", "sms", "twilio", "twitter", "twitter-direct-message", "whatsapp", "yotpo", "yotpo-review", "zendesk"]); export const ticketCustomerChannelCustomer = z.object({id: z.number().int(), name: z.string()}); export const ticketCustomerChannel = z.object({id: z.number().int(), type: z.string(), address: z.string(), preferred: z.boolean().optional(), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string(), user: ticketCustomerChannelCustomer, customer: ticketCustomerChannelCustomer}); export const currency = z.enum(["AFN", "EUR", "ALL", "DZD", "USD", "AOA", "XCD", "ARS", "AMD", "AWG", "AUD", "AZN", "BSD", "BHD", "BDT", "BBD", "BYN", "BZD", "XOF", "BMD", "INR", "BTN", "BOB", "BOV", "BAM", "BWP", "NOK", "BRL", "BND", "BGN", "BIF", "CVE", "KHR", "XAF", "CAD", "KYD", "CLP", "CLF", "CNY", "COP", "COU", "KMF", "CDF", "NZD", "CRC", "HRK", "CUP", "CUC", "ANG", "CZK", "DKK", "DJF", "DOP", "EGP", "SVC", "ERN", "SZL", "ETB", "FKP", "FJD", "XPF", "GMD", "GEL", "GHS", "GIP", "GTQ", "GBP", "GNF", "GYD", "HTG", "HNL", "HKD", "HUF", "ISK", "IDR", "XDR", "IRR", "IQD", "ILS", "JMD", "JPY", "JOD", "KZT", "KES", "KPW", "KRW", "KWD", "KGS", "LAK", "LBP", "LSL", "ZAR", "LRD", "LYD", "CHF", "MOP", "MKD", "MGA", "MWK", "MYR", "MVR", "MRU", "MUR", "XUA", "MXN", "MXV", "MDL", "MNT", "MAD", "MZN", "MMK", "NAD", "NPR", "NIO", "NGN", "OMR", "PKR", "PAB", "PGK", "PYG", "PEN", "PHP", "PLN", "QAR", "RON", "RUB", "RWF", "SHP", "WST", "STN", "SAR", "RSD", "SCR", "SLL", "SLE", "SGD", "XSU", "SBD", "SOS", "SSP", "LKR", "SDG", "SRD", "SEK", "CHE", "CHW", "SYP", "TWD", "TJS", "TZS", "THB", "TOP", "TTD", "TND", "TRY", "TMT", "UGX", "UAH", "AED", "USN", "UYU", "UYI", "UYW", "UZS", "VUV", "VES", "VED", "VND", "YER", "ZMW", "ZWL", "XBA", "XBB", "XBC", "XBD", "XTS", "XXX", "XAU", "XPD", "XPT", "XAG"]); export const storeType = z.enum(["bigcommerce", "magento", "shopify", "woocommerce"]); export const store = z.object({id: z.number().int(), currencies: z.array(currency), default_currency: currency, display_name: z.string(), name: z.string(), type: storeType, url: z.string(), helpdesk_integration_id: z.number().int(), uuid: z.string(), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string()}); export const shopperStatus = z.enum(["tax_exempt", "veteran"]); export const shopper = z.object({id: z.number().int(), external_id: z.string(), helpdesk_customer_id: z.number().int(), email_address: z.string(), phone_number: z.string(), first_name: z.string(), middle_name: z.string(), last_name: z.string(), birthdate: z.string(), status: shopperStatus, accepts_marketing_email: z.boolean(), accepts_marketing_sms: z.boolean(), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string()}); export const status = z.enum(["partially_fulfilled", "completed", "canceled", "on_hold", "awaiting_fulfillment", "awaiting_payment", "scheduled", "order_pending"]); export const paymentStatus = z.enum(["refunded", "partially_refunded", "unpaid", "voided", "failed", "manual_verification_required", "customer_authentication_required", "paid", "declined", "authorized"]); export const shopperAddress = z.object({id: z.number().int(), external_id: z.string(), shopper_external_id: z.string(), preferred: z.boolean(), line_1: z.string(), line_2: z.string(), city: z.string(), state: z.string(), country: z.string(), zip_code: z.string(), first_name: z.string(), last_name: z.string(), phone_number: z.string(), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string()}); export const discountType = z.enum(["percentage", "fixed_amount"]); export const orderLine = z.object({id: z.number().int(), title: z.string(), taxable: z.boolean(), requires_shipping: z.boolean(), unit_price: z.union([z.number(), z.string()]), discount_amount: z.union([z.number(), z.string()]), discount_type: discountType, discount_reason: z.string(), quantity: z.number().int(), total_amount: z.union([z.number(), z.string()]), product_options: z.object({}), fulfilled_quantity: z.number().int(), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string()}); export const order = z.object({id: z.number().int(), external_id: z.string(), shopper_external_id: z.string(), number: z.number().int(), name: z.string(), currency: currency, discount_codes: z.array(z.string()), discount_amount: z.union([z.number(), z.string()]), subtotal_amount: z.union([z.number(), z.string()]), shipping_amount: z.union([z.number(), z.string()]), tax_amount: z.union([z.number(), z.string()]), total_amount: z.union([z.number(), z.string()]), external_status: z.string(), external_fulfillment_status: z.string(), external_payment_status: z.string(), status: status, payment_status: paymentStatus, billing_address: shopperAddress, shipping_address: shopperAddress, line_items: z.array(orderLine), created_datetime: z.string(), updated_datetime: z.string(), deleted_datetime: z.string()}); export const shopperEcommerceData = z.object({store: store, shopper: shopper, orders: z.array(order), addresses: z.array(shopperAddress)}); export const ticketCustomer = z.object({id: z.number().int(), email: z.string(), name: z.string(), firstname: z.string(), lastname: z.string(), meta: z.unknown(), channels: z.array(ticketCustomerChannel), data: z.unknown(), customer: z.unknown(), integrations: z.object({}), external_id: z.string(), note: z.string(), external_data: z.record(z.string(), z.object({})).optional(), ecommerce_data: z.record(z.string(), shopperEcommerceData).optional()}); export const ticketUser = z.object({id: z.number().int(), email: z.string(), name: z.string(), firstname: z.string(), lastname: z.string(), meta: z.unknown(), bio: z.string()}); export const ticketSummary = z.object({content: z.string(), created_datetime: z.string(), updated_datetime: z.string(), triggered_by: z.number().int()}); export const ticketMeta = z.unknown(); export const ticketTagDecoration = z.object({color: z.string().optional()}); export const ticketTag = z.object({id: z.number().int(), name: z.string(), decoration: ticketTagDecoration}); export const eventObjectType = z.enum(["Account", "AccountSetting", "Customer", "CustomField", "CustomFieldCondition", "CustomUserAvailabilityStatus", "CustomerExternalData", "Integration", "Macro", "Order", "Role", "Rule", "SatisfactionSurvey", "Shopper", "ShopperAddress", "Subscription", "Tag", "Team", "TicketMessage", "Ticket", "User", "UserSetting", "View", "Widget"]); export const requirementType = z.enum(["visible", "required", "conditional"]); export const managedTicketFieldType = z.enum(["contact_reason", "product", "resolution", "ai_intent", "ai_outcome", "ai_sales", "ai_discount", "ai_journey", "managed_sentiment", "call_status"]); export const inputSettingsNumber = z.object({input_type: z.literal("input_number"), placeholder: z.string().optional(), min: z.union([z.number(), z.string()]).optional(), max: z.union([z.number(), z.string()]).optional()}); export const definitionNumber = z.object({data_type: z.literal("number"), input_settings: inputSettingsNumber}); export const inputSettingsText = z.object({input_type: z.literal("input"), placeholder: z.string().optional()}); export const inputSettingsDropdownStr = z.object({input_type: z.literal("dropdown"), choices: z.array(z.string()), default: z.string().optional()}); export const definitionText = z.object({data_type: z.literal("text"), input_settings: z.discriminatedUnion("input_type", [inputSettingsText, inputSettingsDropdownStr])}); export const inputSettingsDropdownBool = z.object({input_type: z.literal("dropdown"), choices: z.array(z.boolean()), default: z.boolean().optional()}); export const definitionBoolean = z.object({data_type: z.literal("boolean"), input_settings: inputSettingsDropdownBool}); export const ticketCustomField = z.object({id: z.number().int().gt(0), external_id: z.string().optional(), object_type: eventObjectType, label: z.string(), description: z.string().optional(), priority: z.number().int(), required: z.boolean(), requirement_type: requirementType, managed_type: managedTicketFieldType.optional(), definition: z.discriminatedUnion("data_type", [definitionNumber, definitionText, definitionBoolean]), created_datetime: z.string(), updated_datetime: z.string().optional(), deactivated_datetime: z.string().optional()}); export const ticketCustomFieldValue = z.object({field: ticketCustomField.optional(), id: z.number().int().optional(), prediction: z.unknown(), value: z.unknown()}); export const ticketMessageSourceAddress = z.object({name: z.string().optional(), address: z.string().optional()}); export const ticketMessageSource = z.object({type: z.string(), to: z.array(ticketMessageSourceAddress).optional(), cc: z.array(ticketMessageSourceAddress).optional(), bcc: z.array(ticketMessageSourceAddress).optional(), from: ticketMessageSourceAddress.optional(), extra: z.unknown()}); export const ticketMessageUserOrCustomer = z.object({id: z.number().int(), email: z.string(), name: z.string(), firstname: z.string(), lastname: z.string(), meta: z.unknown()}); export const ticketMessageAuthCustomerIdentityService = z.object({id: z.string(), name: z.string()}); export const ticketMessageAuthCustomerIdentity = z.object({service: ticketMessageAuthCustomerIdentityService, identifier: z.string()}); export const ticketMessageIntent = z.object({name: z.string(), rejected: z.boolean(), is_user_feedback: z.boolean()}); export const ticketMessageAttachment = z.object({url: z.string(), name: z.string().optional(), size: z.number().int().optional(), content_type: z.string(), public: z.boolean().optional(), extra: z.unknown()}); export const ticketMessageMacro = z.object({id: z.number().int().gt(0)}); export const ticketMessageSendingError = z.object({error: z.string()}); export const ticketMessageRepliedByOrTo = z.object({integration_id: z.number().int(), message_id: z.string(), created_datetime: z.string(), body_text: z.string(), source: ticketMessageSource, customer: ticketMessageUserOrCustomer, user: ticketMessageUserOrCustomer}); export const ticketMessage = z.object({id: z.number().int(), uri: z.string(), message_id: z.string(), ticket_id: z.number().int(), external_id: z.string(), public: z.boolean().optional(), channel: z.union([legacyChannelSlug, z.string()]), via: ticketVia, source: ticketMessageSource, sender: ticketMessageUserOrCustomer, auth_customer_identity: ticketMessageAuthCustomerIdentity, integration_id: z.number().int(), intents: z.array(ticketMessageIntent), rule_id: z.number().int(), from_agent: z.boolean(), receiver: ticketMessageUserOrCustomer, subject: z.string(), body_text: z.string(), body_html: z.string(), body_url: z.string(), stripped_text: z.string(), stripped_html: z.string(), stripped_signature: z.string(), attachments: z.array(ticketMessageAttachment), macros: z.array(ticketMessageMacro).optional(), actions: z.array(z.object({})), headers: z.object({}).optional(), imported: z.boolean(), meta: z.unknown(), created_datetime: z.string(), processed_datetime: z.string(), deleted_datetime: z.string().optional(), sent_datetime: z.string(), failed_datetime: z.string(), opened_datetime: z.string(), last_sending_error: ticketMessageSendingError, is_retriable: z.boolean(), replied_by: ticketMessageRepliedByOrTo.optional(), replied_to: ticketMessageRepliedByOrTo.optional()}); export const ticketSatisfactionSurvey = z.object({id: z.number().int(), customer_id: z.number().int(), ticket_id: z.number().int(), sent_datetime: z.string(), scored_datetime: z.string(), should_send_datetime: z.string(), created_datetime: z.string(), score: z.number().int().gte(1).lte(5), body_text: z.string().max(1000), meta: z.object({})}); export const ticketReplyOptionIntegration = z.object({id: z.number().int(), name: z.string(), address: z.string()}); export const ticketReplyOption = z.object({answerable: z.boolean(), reason: z.string().optional(), integrations: z.array(ticketReplyOptionIntegration).optional()}); export const ticket = z.object({id: z.number().int(), uri: z.string(), external_id: z.string(), events: z.array(ticketEvent), status: ticketStatus.optional(), channel: z.union([legacyChannelSlug, z.string()]), via: ticketVia, from_agent: z.boolean(), spam: z.boolean(), imported: z.boolean(), customer: ticketCustomer, assignee_user: ticketUser, language: z.string(), subject: z.string(), summary: ticketSummary.optional(), meta: ticketMeta, tags: z.array(ticketTag), custom_fields: z.record(z.string(), ticketCustomFieldValue).optional(), messages: z.array(ticketMessage), created_datetime: z.string(), processed_datetime: z.string(), opened_datetime: z.string(), last_received_message_datetime: z.string(), last_message_datetime: z.string(), updated_datetime: z.string(), closed_datetime: z.string(), trashed_datetime: z.string(), snooze_datetime: z.string(), satisfaction_survey: ticketSatisfactionSurvey, reply_options: z.record(z.string(), ticketReplyOption), is_unread: z.boolean()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Create a ticket * * POST /api/tickets */ export const createApiApiTickets = async (args: CreateApiApiTicketsArgs, options?: CreateApiApiTicketsOptions) => { const {baseUrl = "https://your-domain.gorgias.com", fetch: fetchFn = fetch, basicAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (basicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${basicAuth.username}:${basicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/api/tickets${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(ticket, await res.json()) };