# Các endpoint REST API

The Ha Tang REST API: email, support (chat) and payments. Authenticate with `Authorization: Bearer ht_...`. Every error uses the `{statusCode, name, message}` envelope. Send `Idempotency-Key` on `POST /emails` to make retries safe.

Base URL: https://api.hatang.dev

## Emails

- `POST /emails`: Send an email
- `GET /emails`: List emails
- `POST /emails/batch`: Send up to 100 emails in one call
- `GET /emails/{id}`: Retrieve an email
- `PATCH /emails/{id}`: Reschedule a scheduled email
- `GET /emails/{id}/events`: Delivery events and per-recipient status
- `POST /emails/{id}/cancel`: Cancel a scheduled email

## Receiving

- `GET /emails/receiving`: List received emails (domains with receiving on; needs email:read)
- `GET /emails/receiving/{id}`: Retrieve a received email: text, HTML, headers and attachment metadata
- `GET /emails/receiving/{id}/attachments`: List a received email's attachments with download URLs (valid for an hour)
- `GET /emails/receiving/{id}/attachments/{attachment_id}`: Retrieve one attachment with a download URL
- `GET /files/received/{attachment_id}`: Download a received attachment (the signed download_url; no API key)

## Domains

- `POST /domains`: Add a domain
- `GET /domains`: List domains
- `GET /domains/{id}`: Retrieve a domain
- `PATCH /domains/{id}`: Update tracking or TLS settings
- `DELETE /domains/{id}`: Delete a domain
- `POST /domains/{id}/verify`: Check the DNS records now and keep re-checking
- `GET /domains/{id}/dns-provider`: Detect the DNS host (Cloudflare or other) and the zone holding the records
- `GET /domains/{id}/domain-connect`: Is one-click DNS setup (Domain Connect) available at this domain's DNS host?
- `POST /domains/{id}/domain-connect`: Start Domain Connect: get the signed URL to send the user to their DNS host

## API Keys

- `POST /api-keys`: Create an API key
- `GET /api-keys`: List API keys
- `DELETE /api-keys/{id}`: Revoke an API key

## Webhooks

- `POST /webhooks`: Create a webhook endpoint
- `GET /webhooks`: List webhooks
- `GET /webhooks/{id}`: Retrieve a webhook
- `PATCH /webhooks/{id}`: Update a webhook
- `DELETE /webhooks/{id}`: Delete a webhook
- `POST /webhooks/{id}/rotate`: Rotate the signing secret (old secret stays valid 24h)
- `GET /webhooks/{id}/deliveries`: Recent delivery attempts
- `POST /webhooks/deliveries/{deliveryId}/replay`: Re-send a delivery with the same svix-id

## Audiences

- `POST /audiences`: Create an audience
- `GET /audiences`: List audiences
- `GET /audiences/{id}`: Retrieve an audience
- `DELETE /audiences/{id}`: Delete an audience and its contacts

## Contacts

- `POST /audiences/{id}/contacts`: Create or update a contact
- `GET /audiences/{id}/contacts`: List contacts
- `GET /audiences/{id}/contacts/{contact}`: Retrieve a contact by id or email
- `PATCH /audiences/{id}/contacts/{contact}`: Update a contact
- `DELETE /audiences/{id}/contacts/{contact}`: Delete a contact
- `POST /contacts`: Create a contact (or update the one with that email)
- `GET /contacts`: List contacts
- `GET /contacts/{id}`: Retrieve a contact by id or email
- `PATCH /contacts/{id}`: Update a contact
- `DELETE /contacts/{id}`: Delete a contact
- `GET /contacts/{id}/segments`: Segments the contact belongs to
- `POST /contacts/{id}/segments/{segment}`: Add the contact to a segment
- `DELETE /contacts/{id}/segments/{segment}`: Remove the contact from a segment
- `GET /contacts/{id}/topics`: The contact's subscription to every topic
- `PATCH /contacts/{id}/topics`: Set the contact's topic subscriptions

## Broadcasts

- `POST /broadcasts`: Create a broadcast draft
- `GET /broadcasts`: List broadcasts
- `GET /broadcasts/{id}`: Retrieve a broadcast
- `PATCH /broadcasts/{id}`: Update a draft or scheduled broadcast
- `DELETE /broadcasts/{id}`: Delete a broadcast
- `POST /broadcasts/{id}/send`: Send now or schedule
- `POST /broadcasts/{id}/cancel`: Cancel a scheduled broadcast

## Templates

- `POST /templates`: Create a template (draft)
- `GET /templates`: List templates
- `GET /templates/{id}`: Retrieve a template by id or alias
- `PATCH /templates/{id}`: Update the draft of a template
- `DELETE /templates/{id}`: Delete a template
- `POST /templates/{id}/publish`: Publish the draft; sends use the published version
- `POST /templates/{id}/duplicate`: Copy a template as a new draft

## Metrics

- `GET /emails/metrics`: Email metrics per period (and domain): counts and rates

## Logs

- `GET /logs`: API request logs, newest first
- `GET /logs/{id}`: One request log with its request and response bodies (secrets redacted)

## Usage

- `GET /usage`: What the business used against its limits

## Segments

- `POST /segments`: Create a segment
- `GET /segments`: List segments
- `GET /segments/{id}`: Retrieve a segment with its contact count
- `PATCH /segments/{id}`: Rename a segment
- `DELETE /segments/{id}`: Delete a segment (its contacts stay)
- `GET /segments/{id}/contacts`: Contacts in a segment

## Topics

- `POST /topics`: Create a topic
- `GET /topics`: List topics
- `GET /topics/{id}`: Retrieve a topic
- `PATCH /topics/{id}`: Update a topic's name, description or visibility
- `DELETE /topics/{id}`: Delete a topic

## Contact properties

- `POST /contact-properties`: Declare a contact property
- `GET /contact-properties`: List contact properties
- `PATCH /contact-properties/{id}`: Change a property's fallback value
- `DELETE /contact-properties/{id}`: Delete a property and its values

## Events

- `POST /events`: Define a custom event (name and payload schema)
- `GET /events`: List event definitions
- `POST /events/send`: Send an event for a contact: starts automations triggered by it and resumes runs waiting for it
- `GET /events/{id}`: Retrieve an event definition by id or name
- `PATCH /events/{id}`: Change an event's payload schema
- `DELETE /events/{id}`: Delete an event definition

## Automations

- `POST /automations`: Create an automation (steps and connections)
- `GET /automations`: List automations
- `GET /automations/{id}`: Retrieve an automation
- `PATCH /automations/{id}`: Update an automation; steps can only change while it is disabled
- `DELETE /automations/{id}`: Delete an automation and its runs
- `POST /automations/{id}/stop`: Disable the automation and cancel its runs in flight
- `POST /automations/{id}/duplicate`: Copy an automation as a new disabled one
- `GET /automations/{id}/runs`: Runs of an automation
- `GET /automations/{id}/runs/{run_id}`: One run with its steps

## Chat sites

- `POST /chat/sites`: Add an extra chat site on a subdomain (the domain's own widget is created automatically)
- `GET /chat/sites`: List chat sites
- `GET /chat/sites/{id}`: Retrieve a site
- `PATCH /chat/sites/{id}`: Update a site's settings, origins or status
- `DELETE /chat/sites/{id}`: Delete a site and everything under it
- `POST /chat/sites/{id}/identity-secret`: Rotate the secret used to sign identify() calls
- `GET /chat/profile-links`: The business's profile links (URL templates agents open for the person in a conversation)
- `PUT /chat/profile-links`: Replace the profile links (max 10; https, known {{variables}}, none in the host)
- `GET /chat/sites/{id}/kb/sources`: List the business's knowledge sources
- `POST /chat/sites/{id}/kb/sources`: Add a knowledge source (FAQ, text or website crawl); indexing runs in the background
- `GET /chat/sites/{id}/kb/sources/{sourceId}`: Get a knowledge source
- `PATCH /chat/sites/{id}/kb/sources/{sourceId}`: Update a knowledge source and re-index it
- `DELETE /chat/sites/{id}/kb/sources/{sourceId}`: Delete a knowledge source and its chunks
- `POST /chat/sites/{id}/kb/sources/{sourceId}/reindex`: Re-index a knowledge source
- `POST /chat/sites/{id}/kb/files`: Upload a PDF or DOCX as a knowledge source (multipart: file, optional title). Text is extracted on upload, up to 20 MB; scanned PDFs need OCR first.
- `GET /chat/sites/{id}/kb/search`: Search the knowledge base the assistant answers from (keyword and semantic matches, fused by rank)
- `GET /chat/subscriptions`: List subscriptions (web, App Store, Google Play); filter by external_user_id, platform, status (comma-separated)
- `PUT /chat/subscriptions/{platform}/{original_id}`: Create or update a subscription from your backend (App Store and Google Play ones also arrive from the stores once connected)
- `POST /chat/subscriptions/{id}/refresh`: Ask the App Store / Google Play about one subscription again (needs the app's App Store Server API key or Play service account)
- `POST /chat/subscriptions/import`: Import existing subscribers of an app: Apple transaction ids (any of the customer's; their one-time purchases come too) or Google Play purchase tokens, up to 500 per call
- `GET /chat/sites/{id}/purchase-token`: The app account token of one of your users: pass it as Apple appAccountToken / Google obfuscatedExternalAccountId when buying

## Conversations

- `GET /chat/conversations`: List conversations
- `GET /chat/conversations/{id}`: Retrieve a conversation
- `PATCH /chat/conversations/{id}`: Assign, change status or replace tags
- `GET /chat/conversations/{id}/messages`: Timeline (messages and events) of a conversation
- `POST /chat/conversations/{id}/messages`: Send a message as your team (Idempotency-Key supported)
- `POST /chat/conversations/{id}/products`: Send product cards into a conversation
- `POST /chat/conversations/{id}/flows/{flowId}`: Start a flow in a conversation right now
- `POST /chat/conversations/{id}/workflows/{workflowId}`: Run a workflow for a conversation now (its trigger conditions are skipped)
- `POST /chat/conversations/{id}/workflows/stop`: Stop every running or waiting workflow run in a conversation

## Customers

- `GET /chat/customers`: List customers (one person across channels)
- `GET /chat/customers/export.csv`: Export the matching customers as CSV
- `GET /chat/customers/merge-suggestions`: Pairs of customers that share an e-mail or phone number
- `GET /chat/customers/{id}`: Retrieve a customer with their visitors
- `PATCH /chat/customers/{id}`: Update contact details, owner, stage, labels or custom fields
- `POST /chat/customers/{id}/merge`: Merge another customer into this one
- `GET /chat/customers/{id}/conversations`: A customer's conversations across all channels
- `GET /chat/customer-fields`: List custom customer fields
- `POST /chat/customer-fields`: Create a custom customer field
- `PATCH /chat/customer-fields/{id}`: Update a custom customer field
- `DELETE /chat/customer-fields/{id}`: Delete a custom customer field
- `GET /chat/customers/{id}/subscriptions`: A customer's subscriptions, newest first
- `GET /chat/customers/{id}/purchases`: A customer's one-time in-app purchases (consumable, non-consumable, non-renewing), verified with the App Store or Google Play, newest first

## Products

- `GET /chat/products`: List catalog products
- `POST /chat/products`: Add a product
- `GET /chat/products/search`: Relevance search over the catalog (accent-insensitive)
- `GET /chat/products/categories`: Distinct product categories
- `POST /chat/products/import`: Import products from CSV text, a CSV/Google Sheets link, or a website's schema.org Product JSON-LD
- `GET /chat/products/{id}`: Retrieve a product
- `PATCH /chat/products/{id}`: Update a product
- `DELETE /chat/products/{id}`: Delete a product

## Orders

- `GET /chat/orders`: List orders
- `POST /chat/orders`: Create an order (optionally from a conversation, posting an order card)
- `GET /chat/orders/stats`: Orders per stage and paid revenue
- `GET /chat/orders/{id}`: Retrieve an order by id or code
- `PATCH /chat/orders/{id}`: Update items, stage, address or note
- `POST /chat/orders/{id}/payment-link`: Create a VietQR payment for the order and post it into the conversation

## ZNS

- `GET /chat/zns/templates`: Approved ZNS templates of a Zalo OA account (with the daily quota)
- `GET /chat/zns/templates/{id}`: A ZNS template with its parameters
- `GET /chat/zns`: ZNS messages sent by the team
- `POST /chat/zns`: Send one ZNS template message to a phone number (billed by Zalo)
- `POST /chat/zns/bulk`: Queue a ZNS template to every customer matching the filters (one message per customer with a phone)

## Reports and ratings

- `GET /chat/reports`: Support report for a date range: overview, per-day, per-agent, channels, tags (defaults to the last 30 days)
- `GET /chat/ratings`: CSAT ratings in a date range

## Tickets

- `GET /chat/tickets`: List tickets
- `POST /chat/tickets`: Create a ticket (SLA deadlines follow the team policy)
- `GET /chat/tickets/stats`: Open, overdue, unassigned counts and this week's resolution figures
- `GET /chat/tickets/{id}`: Retrieve a ticket by id or code (TK000123)
- `PATCH /chat/tickets/{id}`: Update a ticket (status, priority, assignee, due date…)
- `DELETE /chat/tickets/{id}`: Delete a ticket
- `GET /chat/sla`: The team's SLA policy (minutes per priority)
- `PUT /chat/sla`: Replace the SLA policy

## Flows

- `GET /chat/flows`: List scripted flows
- `POST /chat/flows`: Create a scripted flow (trigger + steps)
- `GET /chat/flows/templates`: Ready-made flow templates
- `GET /chat/flows/{id}`: Retrieve a flow
- `PATCH /chat/flows/{id}`: Replace a flow's definition
- `DELETE /chat/flows/{id}`: Delete a flow

## Workflows

- `GET /chat/workflows`: List workflows (event-driven automation)
- `POST /chat/workflows`: Create a workflow: a trigger event, optional conditions and a list of steps
- `GET /chat/workflows/templates`: Ready-made workflow templates
- `GET /chat/workflows/{id}`: Retrieve a workflow
- `PATCH /chat/workflows/{id}`: Replace a workflow's definition
- `DELETE /chat/workflows/{id}`: Delete a workflow
- `GET /chat/workflows/{id}/runs`: Recent runs of a workflow, with the log of each step

## Campaigns

- `GET /chat/campaigns`: List widget campaigns
- `POST /chat/campaigns`: Create a campaign (proactive message or lead form)
- `GET /chat/campaigns/{id}`: Retrieve a campaign
- `PATCH /chat/campaigns/{id}`: Update a campaign
- `DELETE /chat/campaigns/{id}`: Delete a campaign

## Visitors

- `GET /chat/live`: Visitors currently on your sites
- `POST /chat/live/greet`: Start a conversation with a visitor who has not written yet
- `GET /chat/visitors/{id}`: Retrieve a visitor
- `PATCH /chat/visitors/{id}`: Update a visitor's identity or custom data
- `DELETE /chat/visitors/{id}`: Anonymise a visitor (GDPR-style delete)
- `GET /chat/visitors/{id}/conversations`: A visitor's conversations

## Knowledge

- `GET /chat/knowledge/documents`: List knowledge documents, in id order
- `POST /chat/knowledge/documents/batch`: Create or update up to 100 documents
- `GET /chat/knowledge/documents/{id}`: Get a knowledge document
- `PUT /chat/knowledge/documents/{id}`: Create or update a knowledge document under your own id; indexing runs in the background
- `DELETE /chat/knowledge/documents/{id}`: Delete a knowledge document
- `POST /chat/knowledge/collections/{name}/sync`: Make a collection hold exactly these documents (up to 1,000): listed ones are written, the rest of the collection deleted
- `GET /chat/knowledge/search`: Search the knowledge the assistant answers from, preferring a language

## Canned responses

- `GET /chat/canned-responses`: List canned responses
- `POST /chat/canned-responses`: Create a canned response
- `PATCH /chat/canned-responses/{id}`: Update a canned response
- `DELETE /chat/canned-responses/{id}`: Delete a canned response

## Routing rules

- `GET /chat/routing-rules`: List distribution rules (evaluated top-down by position)
- `POST /chat/routing-rules`: Create a distribution rule
- `POST /chat/routing-rules/reorder`: Reorder distribution rules
- `PATCH /chat/routing-rules/{id}`: Update a distribution rule
- `DELETE /chat/routing-rules/{id}`: Delete a distribution rule

## Payments

- `POST /payments`: Create a payment (Idempotency-Key supported)
- `GET /payments`: List payments
- `GET /payments/{id}`: Retrieve a payment
- `GET /payments/{id}/ipn-deliveries`: IPN calls made for this payment (newest first)
- `POST /payments/{id}/cancel`: Cancel a pending payment
- `POST /payments/{id}/mark-paid`: Record money received outside the bank feed
- `GET /payments/qr`: VietQR for any amount and description (webhook-only integrations; nothing is stored)
- `POST /payments/simulate/transfer`: Simulate a bank transfer (development only)

## Transactions

- `GET /payments/transactions`: List bank transactions
- `GET /payments/transactions/{id}`: Retrieve a transaction
- `POST /payments/statements`: Import a bank statement (CSV) to recover transactions the bank never pushed
- `GET /payments/statements/{id}`: Statement import progress
- `POST /payments/transactions/{id}/invoice-exempt`: Mark money in as needing no invoice (left out of invoice reconciliation)
- `DELETE /payments/transactions/{id}/invoice-exempt`: Put the transaction back into invoice reconciliation

## Bank connections

- `GET /payments/bank-connections`: List linked bank accounts
- `POST /payments/bank-connections`: Start linking a bank account; the bank texts a code to the holder
- `GET /payments/bank-connections/{id}`: Retrieve a bank connection
- `PATCH /payments/bank-connections/{id}`: Change the label or matching settings
- `POST /payments/bank-connections/{id}/confirm`: Confirm linking with the code
- `POST /payments/bank-connections/{id}/unlink`: Start unlinking; returns a challenge when the bank confirms with a code
- `POST /payments/bank-connections/{id}/unlink/confirm`: Confirm unlinking with the code
- `POST /payments/bank-connections/{id}/acb/notification`: ACB: register the transaction-notification service (a code follows)
- `PUT /payments/bank-connections/{id}/acb/notification`: ACB: change which transactions are notified (a code follows)
- `DELETE /payments/bank-connections/{id}/acb/notification`: ACB: cancel the notification service (a code follows)
- `GET /payments/bank-connections/{id}/acb/notification`: ACB: what the holder has registered
- `POST /payments/bank-connections/{id}/acb/notification/confirm`: ACB: confirm a notification registration, change or cancellation with the code
- `GET /payments/bank-connections/{id}/acb/virtual-accounts`: ACB: the virtual accounts under this account
- `GET /payments/acb/virtual-accounts`: ACB: the virtual accounts an account already has, before it is linked — pick one in config.acb.virtual_account_number to adopt it instead of opening another
- `GET /payments/acb/notifications`: ACB: every account registered for notifications under this partner

## E-invoices

- `GET /einvoices/reconciliation`: Money in against invoices: what has one, what is missing one, what needs none, per day
- `GET /einvoices/providers`: Providers you can connect, with the fields each needs
- `POST /einvoices/connections/check`: Check provider credentials and list the account's templates (nothing is saved)
- `GET /einvoices/connections`: List e-invoice provider connections
- `POST /einvoices/connections`: Connect an e-invoice provider account (credentials and template are checked)
- `GET /einvoices/connections/{id}`: Retrieve a provider connection
- `DELETE /einvoices/connections/{id}`: Unlink a provider (its invoices are kept; the next provider becomes the default)
- `PATCH /einvoices/connections/{id}`: Change default mode, template, credentials or make it the default
- `POST /einvoices/connections/{id}/default`: Make this the default provider
- `GET /einvoices/connections/{id}/templates`: Templates this provider account may issue on
- `POST /einvoices/connections/{id}/sync`: Check every draft and unsettled invoice of this connection at the provider now
- `POST /einvoices`: Create an invoice: the draft is created first, then (mode publish) sent for approval
- `GET /einvoices`: List invoices
- `GET /einvoices/{id}`: Retrieve an invoice
- `PATCH /einvoices/{id}`: Edit a draft
- `DELETE /einvoices/{id}`: Delete a draft
- `POST /einvoices/{id}/publish`: Send a draft for approval (sign and issue it)
- `POST /einvoices/{id}/retry`: Run the failed step again
- `POST /einvoices/{id}/replace`: Issue a replacement invoice
- `POST /einvoices/{id}/resolve`: Settle a conflict: keep your draft or the provider's
- `POST /einvoices/{id}/sync`: Check this invoice at the provider now
- `GET /einvoices/{id}/history`: Status history (who changed what, on which side)

## Checkout

- `GET /pay/{id}`: What the hosted checkout page shows
- `GET /pay/{id}/qr.svg`: VietQR image, with the hatang mark in the middle unless `logo=0`
- `GET /pay/{id}/events`: Server-sent events with the payment status

## Integrations

- `GET /integrations/{provider}/{action}`: Provider callback (verification)
- `POST /integrations/{provider}/{action}`: Provider callback: MB Bank token (API 32) and balance change (API 90); e-invoice status changes

## Tracking

- `POST /stores/apple/{appId}`: App Store Server Notifications v2 for one connected app (Apple-signed JWS in signedPayload)
- `POST /stores/google/{appId}`: Google Play real-time developer notifications (Pub/Sub push) for one connected app
- `GET /channels/{channel}/webhook`: Channel webhook verification (Zalo, Messenger)
- `POST /channels/{channel}/webhook`: Channel webhook receiver
- `GET /o/{token}`: Open-tracking pixel
- `GET /c/{token}`: Click redirect
- `GET /internal/tls-ask`: On-demand TLS check used by the reverse proxy
- `POST /ses/events`: Amazon SNS endpoint for SES delivery, bounce and complaint events (SES mode only)
- `POST /ses/inbound`: Amazon SNS endpoint for mail SES received for the chat inbox domain (stored in S3)
- `GET /u/{token}`: Email preferences page (topics, unsubscribe from all); opening it changes nothing
- `POST /u/{token}`: One-click unsubscribe (RFC 8058): from the topic in the link, else from everything
- `POST /u/{token}/preferences`: Save the preferences page form
