@letsbot/sdk 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73,6 +73,8 @@ tags:
73
73
  description: Connection (instance) status, presence and settings.
74
74
  - name: Products
75
75
  description: Catalog products, collections and orders.
76
+ - name: Orders
77
+ description: Record orders from your own store system (not Salla / Zid) to start the order journey and send the invoice.
76
78
  - name: Session
77
79
  description: QR linking and session state (QR-linked channels).
78
80
  - name: Archive
@@ -82,7 +84,7 @@ tags:
82
84
  authenticated with `X-Zapier-Api-Key`. Its operations carry their own `servers` and `security`.'
83
85
  - name: CRM
84
86
  description: 'The public CRM API at https://{workspace}.letsbot.net/api/v1/crm — contacts, companies, deals, tasks, activities,
85
- quotes, products and REST-hook webhooks. Workspace API key (`X-Zapier-Api-Key`) with the `crm` scope ticked; the key acts
87
+ quotes, products, custom objects and REST-hook webhooks. Workspace API key (`X-Zapier-Api-Key`) with the `crm` scope ticked; the key acts
86
88
  for the whole workspace. Envelope `{success, data, meta?}` / `{success: false, error, code, errors?}`; 120 requests per
87
89
  minute per key.'
88
90
  paths:
@@ -4850,6 +4852,192 @@ paths:
4850
4852
  $ref: '#/components/responses/InternalError'
4851
4853
  '503':
4852
4854
  $ref: '#/components/responses/LifecycleUnavailable'
4855
+ /orders:
4856
+ post:
4857
+ operationId: recordOrder
4858
+ tags:
4859
+ - Orders
4860
+ summary: Record an order (order journey + invoice)
4861
+ description: |-
4862
+ For merchants whose orders live in their own system (not Salla / Zid). Each recorded order starts the order journey: every active automation reminder on «Order placed» (/panel/v2/automation-reminders) goes to this customer N days after `ordered_at` (rating request, discount, marketing…). When the request carries `invoice_url` (https page) or `invoice_pdf_url` (https PDF) the invoice is sent at once, once per order, through the invoices templates (/panel/v2/invoices).
4863
+
4864
+ Recording an order sends nothing by itself, so this is not a send endpoint. A customer who never wrote to the business is reached only on an official (Cloud API) number; `journey.reachable` tells you before the first reminder is due.
4865
+
4866
+ Validation failures always answer HTTP 422 `{"Status": false, "Message": ..., "errors": {...}}`.
4867
+ requestBody:
4868
+ required: true
4869
+ content:
4870
+ application/json:
4871
+ schema:
4872
+ type: object
4873
+ properties:
4874
+ order_id:
4875
+ type: string
4876
+ maxLength: 64
4877
+ pattern: ^[A-Za-z0-9._\-]+$
4878
+ description: Your order id. Used again by the cancel endpoint.
4879
+ examples:
4880
+ - ORD-1042
4881
+ phone:
4882
+ $ref: '#/components/schemas/Phone'
4883
+ customer_name:
4884
+ type: string
4885
+ maxLength: 191
4886
+ ordered_at:
4887
+ type: string
4888
+ format: date-time
4889
+ description: Within the last 365 days and not in the future. Defaults to now.
4890
+ total:
4891
+ type: number
4892
+ minimum: 0
4893
+ currency:
4894
+ type: string
4895
+ maxLength: 8
4896
+ examples:
4897
+ - SAR
4898
+ order_url:
4899
+ type: string
4900
+ format: uri
4901
+ maxLength: 2048
4902
+ description: https only.
4903
+ store_name:
4904
+ type: string
4905
+ maxLength: 191
4906
+ language:
4907
+ type: string
4908
+ enum:
4909
+ - ar
4910
+ - en
4911
+ - es
4912
+ - pt
4913
+ invoice_number:
4914
+ type: string
4915
+ maxLength: 64
4916
+ invoice_url:
4917
+ type: string
4918
+ format: uri
4919
+ maxLength: 2048
4920
+ description: https invoice page; sends the invoice at once.
4921
+ invoice_pdf_url:
4922
+ type: string
4923
+ format: uri
4924
+ maxLength: 2048
4925
+ description: https invoice PDF; sends the invoice at once.
4926
+ products:
4927
+ type: array
4928
+ maxItems: 20
4929
+ items:
4930
+ type: object
4931
+ properties:
4932
+ name:
4933
+ type: string
4934
+ maxLength: 191
4935
+ url:
4936
+ type: string
4937
+ format: uri
4938
+ maxLength: 2048
4939
+ required:
4940
+ - name
4941
+ required:
4942
+ - order_id
4943
+ - phone
4944
+ responses:
4945
+ '201':
4946
+ description: Order recorded.
4947
+ content:
4948
+ application/json:
4949
+ schema:
4950
+ type: object
4951
+ properties:
4952
+ Status:
4953
+ type: boolean
4954
+ Message:
4955
+ type: string
4956
+ order_id:
4957
+ type: string
4958
+ journey:
4959
+ type: object
4960
+ properties:
4961
+ recorded:
4962
+ type: boolean
4963
+ ordered_at:
4964
+ type: string
4965
+ format: date-time
4966
+ reachable:
4967
+ type: boolean
4968
+ description: false = this customer never wrote to you and your number is QR-linked, so journey messages will not reach them.
4969
+ invoice:
4970
+ type: string
4971
+ enum:
4972
+ - not_requested
4973
+ - sent
4974
+ - skipped
4975
+ - failed
4976
+ - duplicate
4977
+ - 'off'
4978
+ '401':
4979
+ $ref: '#/components/responses/Unauthorized'
4980
+ '403':
4981
+ description: No workspace is linked to this API key.
4982
+ '409':
4983
+ description: The workspace is still being prepared. Try again in a few minutes.
4984
+ '422':
4985
+ description: 'Validation failed (`{"Status": false, "Message": ..., "errors": {...}}`), or the phone is not a full international number, or `ordered_at` is out of range.'
4986
+ '429':
4987
+ $ref: '#/components/responses/TooManyRequests'
4988
+ '500':
4989
+ description: The order could not be recorded. Try again.
4990
+ '503':
4991
+ $ref: '#/components/responses/LifecycleUnavailable'
4992
+ /orders/{orderId}/cancel:
4993
+ post:
4994
+ operationId: cancelOrder
4995
+ tags:
4996
+ - Orders
4997
+ summary: Stop the order journey for a cancelled or refunded order
4998
+ description: No further journey messages are sent for this order. Send the customer phone used when the order was recorded.
4999
+ parameters:
5000
+ - name: orderId
5001
+ in: path
5002
+ required: true
5003
+ schema:
5004
+ type: string
5005
+ pattern: ^[A-Za-z0-9._\-]{1,64}$
5006
+ requestBody:
5007
+ required: true
5008
+ content:
5009
+ application/json:
5010
+ schema:
5011
+ type: object
5012
+ properties:
5013
+ phone:
5014
+ $ref: '#/components/schemas/Phone'
5015
+ required:
5016
+ - phone
5017
+ responses:
5018
+ '200':
5019
+ description: OK. `cancelled` is false when no open order matches this id and phone.
5020
+ content:
5021
+ application/json:
5022
+ schema:
5023
+ type: object
5024
+ properties:
5025
+ Status:
5026
+ type: boolean
5027
+ Message:
5028
+ type: string
5029
+ cancelled:
5030
+ type: boolean
5031
+ '401':
5032
+ $ref: '#/components/responses/Unauthorized'
5033
+ '403':
5034
+ description: No workspace is linked to this API key.
5035
+ '422':
5036
+ description: The phone is missing or not a full international number.
5037
+ '429':
5038
+ $ref: '#/components/responses/TooManyRequests'
5039
+ '503':
5040
+ $ref: '#/components/responses/LifecycleUnavailable'
4853
5041
  /product:
4854
5042
  post:
4855
5043
  operationId: getProducts
@@ -10693,10 +10881,21 @@ paths:
10693
10881
  tags:
10694
10882
  - CRM
10695
10883
  summary: Create a contact
10696
- description: "Creates a contact (WhatsApp customer) by phone. A phone that already exists answers 409 with that contact
10697
- in `data`. Scope: `crm`."
10884
+ description: "Creates a contact (WhatsApp customer) by phone. A phone that already exists answers 409 `already_exists`
10885
+ with that contact in `data`. A likely duplicate (the same number in another format, the same WhatsApp username or
10886
+ the same e-mail) answers 409 `possible_duplicate` with `existing_id` and `duplicates` — update that contact, or
10887
+ repeat with `?allow_duplicate=1` to create a new one anyway. Scope: `crm`."
10698
10888
  security:
10699
10889
  - zapierApiKey: []
10890
+ parameters:
10891
+ - name: allow_duplicate
10892
+ in: query
10893
+ required: false
10894
+ description: "`1` / `true`: create the record even when a likely duplicate exists (otherwise 409
10895
+ `possible_duplicate`)."
10896
+ schema:
10897
+ type: boolean
10898
+ default: false
10700
10899
  requestBody:
10701
10900
  required: true
10702
10901
  content:
@@ -11060,9 +11259,20 @@ paths:
11060
11259
  tags:
11061
11260
  - CRM
11062
11261
  summary: Create a company
11063
- description: "Creates a company (account). Scope: `crm`."
11262
+ description: "Creates a company (account). A likely duplicate (the same domain, or the same name once legal forms
11263
+ are ignored) answers 409 `possible_duplicate` with `existing_id` and `duplicates`; repeat with
11264
+ `?allow_duplicate=1` to create it anyway. Scope: `crm`."
11064
11265
  security:
11065
11266
  - zapierApiKey: []
11267
+ parameters:
11268
+ - name: allow_duplicate
11269
+ in: query
11270
+ required: false
11271
+ description: "`1` / `true`: create the record even when a likely duplicate exists (otherwise 409
11272
+ `possible_duplicate`)."
11273
+ schema:
11274
+ type: boolean
11275
+ default: false
11066
11276
  requestBody:
11067
11277
  required: true
11068
11278
  content:
@@ -11145,6 +11355,8 @@ paths:
11145
11355
  $ref: "#/components/responses/CrmForbidden"
11146
11356
  "404":
11147
11357
  $ref: "#/components/responses/CrmNotFound"
11358
+ "409":
11359
+ $ref: "#/components/responses/CrmConflict"
11148
11360
  "422": *a1
11149
11361
  "429":
11150
11362
  $ref: "#/components/responses/TooManyRequests"
@@ -13309,16 +13521,21 @@ paths:
13309
13521
  $ref: "#/components/responses/CrmNotFound"
13310
13522
  "429":
13311
13523
  $ref: "#/components/responses/TooManyRequests"
13312
- /v1/crm/hooks:
13524
+ /v1/crm/objects:
13313
13525
  x-letsbot-surface: zapier
13314
- servers: *a2
13526
+ servers:
13527
+ - url: https://{workspace}.letsbot.net/api
13528
+ description: The workspace's own subdomain. The CRM API lives under /v1/crm.
13529
+ variables:
13530
+ workspace:
13531
+ default: your-workspace
13532
+ description: The workspace subdomain.
13315
13533
  get:
13316
- operationId: crmListHooks
13534
+ operationId: crmListCustomObjects
13317
13535
  tags:
13318
13536
  - CRM
13319
- summary: List API webhook subscriptions
13320
- description: "Subscriptions created through the API (panel-made ones are managed in the panel). Secrets are never
13321
- returned again. Scope: `crm`."
13537
+ summary: List custom objects
13538
+ description: "The workspace's custom CRM objects (for example Projects or Properties) with their fields: key, label, type, options and whether a field is required or read-only (formula, rollup). Available while the workspace uses custom objects (CRM → Custom objects); until then these paths answer `404`. Scope: `crm`."
13322
13539
  security:
13323
13540
  - zapierApiKey: []
13324
13541
  responses:
@@ -13337,7 +13554,7 @@ paths:
13337
13554
  data:
13338
13555
  type: array
13339
13556
  items:
13340
- $ref: "#/components/schemas/CrmWebhookSubscription"
13557
+ $ref: "#/components/schemas/CrmCustomObject"
13341
13558
  "401":
13342
13559
  $ref: "#/components/responses/ZapierUnauthorized"
13343
13560
  "403":
@@ -13346,51 +13563,34 @@ paths:
13346
13563
  $ref: "#/components/responses/CrmNotFound"
13347
13564
  "429":
13348
13565
  $ref: "#/components/responses/TooManyRequests"
13349
- post:
13350
- operationId: crmSubscribeHook
13566
+ /v1/crm/objects/{key}/schema:
13567
+ x-letsbot-surface: zapier
13568
+ servers:
13569
+ - url: https://{workspace}.letsbot.net/api
13570
+ description: The workspace's own subdomain. The CRM API lives under /v1/crm.
13571
+ variables:
13572
+ workspace:
13573
+ default: your-workspace
13574
+ description: The workspace subdomain.
13575
+ get:
13576
+ operationId: crmCustomObjectSchema
13351
13577
  tags:
13352
13578
  - CRM
13353
- summary: Subscribe a webhook (REST hook)
13354
- description: 'Zapier / Make / n8n REST-hook subscribe. Accepts `target_url` or `url`, and `event` or `events`. The
13355
- answer carries the signing `secret` ONCE. Deliveries are POSTed as CrmWebhookEvent with `X-LetsBot-Signature:
13356
- t=<unix>,v1=<hex HMAC-SHA256 of "t.body">`, `X-LetsBot-Event` and `X-LetsBot-Delivery`; failed deliveries are
13357
- retried with backoff (1 min, 5 min, 30 min, 2 h, 6 h); after 5 deliveries in a row fail the subscription is
13358
- switched off, and an HTTP 410 answer switches it off at once. Scope: `crm`.'
13579
+ summary: Custom object fields, filters and sorts
13580
+ description: "The object (as in the list) plus the lists-engine catalogue of its records: every field with its type, whether it can be filtered or sorted, and the filter operators. Scope: `crm`."
13359
13581
  security:
13360
13582
  - zapierApiKey: []
13361
- requestBody:
13362
- required: true
13363
- content:
13364
- application/json:
13365
- schema:
13366
- type: object
13367
- properties:
13368
- target_url:
13369
- type: string
13370
- format: uri
13371
- url:
13372
- type: string
13373
- format: uri
13374
- event:
13375
- $ref: "#/components/schemas/CrmWebhookEventName"
13376
- events:
13377
- type: array
13378
- items:
13379
- $ref: "#/components/schemas/CrmWebhookEventName"
13380
- source:
13381
- type: string
13382
- enum:
13383
- - zapier
13384
- - make
13385
- - n8n
13386
- - api
13387
- description:
13388
- type:
13389
- - string
13390
- - "null"
13583
+ parameters:
13584
+ - name: key
13585
+ in: path
13586
+ required: true
13587
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13588
+ schema:
13589
+ type: string
13590
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13391
13591
  responses:
13392
- "201":
13393
- description: Subscribed.
13592
+ "200":
13593
+ description: OK
13394
13594
  content:
13395
13595
  application/json:
13396
13596
  schema:
@@ -13403,76 +13603,580 @@ paths:
13403
13603
  const: true
13404
13604
  data:
13405
13605
  allOf:
13406
- - $ref: "#/components/schemas/CrmWebhookSubscription"
13407
13606
  - type: object
13408
- required:
13409
- - secret
13607
+ description: The object (as in GET /v1/crm/objects, without its `fields`).
13410
13608
  properties:
13411
- secret:
13609
+ key:
13610
+ type: string
13611
+ label_singular:
13612
+ type: object
13613
+ additionalProperties:
13614
+ type: string
13615
+ label_plural:
13616
+ type: object
13617
+ additionalProperties:
13618
+ type: string
13619
+ primary_field:
13412
13620
  type: string
13621
+ - $ref: "#/components/schemas/CrmListSchema"
13413
13622
  "401":
13414
13623
  $ref: "#/components/responses/ZapierUnauthorized"
13415
13624
  "403":
13416
13625
  $ref: "#/components/responses/CrmForbidden"
13417
13626
  "404":
13418
13627
  $ref: "#/components/responses/CrmNotFound"
13419
- "422": *a1
13420
13628
  "429":
13421
13629
  $ref: "#/components/responses/TooManyRequests"
13422
- /v1/crm/hooks/events:
13630
+ /v1/crm/objects/{key}/records:
13423
13631
  x-letsbot-surface: zapier
13424
- servers: *a2
13632
+ servers:
13633
+ - url: https://{workspace}.letsbot.net/api
13634
+ description: The workspace's own subdomain. The CRM API lives under /v1/crm.
13635
+ variables:
13636
+ workspace:
13637
+ default: your-workspace
13638
+ description: The workspace subdomain.
13425
13639
  get:
13426
- operationId: crmListHookEvents
13640
+ operationId: crmListCustomRecords
13427
13641
  tags:
13428
13642
  - CRM
13429
- summary: List webhook events
13430
- description: "The event catalogue. Scope: `crm`."
13643
+ summary: List custom records
13644
+ description: "Records of one custom object through the CRM lists engine: search, filters, saved views, sort and pages. Scope: `crm`."
13431
13645
  security:
13432
13646
  - zapierApiKey: []
13433
- responses:
13434
- "200":
13435
- description: OK
13436
- content:
13437
- application/json:
13438
- schema:
13439
- type: object
13440
- required:
13441
- - success
13442
- - data
13443
- properties:
13444
- success:
13445
- const: true
13446
- data:
13447
- type: array
13448
- items:
13449
- type: object
13450
- required:
13451
- - event
13452
- - object
13453
- properties:
13454
- event:
13455
- $ref: "#/components/schemas/CrmWebhookEventName"
13456
- object:
13457
- type: string
13458
- "401":
13459
- $ref: "#/components/responses/ZapierUnauthorized"
13460
- "403":
13461
- $ref: "#/components/responses/CrmForbidden"
13462
- "404":
13463
- $ref: "#/components/responses/CrmNotFound"
13464
- "429":
13465
- $ref: "#/components/responses/TooManyRequests"
13466
- /v1/crm/hooks/sample:
13467
- x-letsbot-surface: zapier
13468
- servers: *a2
13469
- get:
13470
- operationId: crmHookSample
13471
- tags:
13472
- - CRM
13473
- summary: Sample webhook payload
13474
- description: "One sample event built from the newest record of that object (empty when there is none) — for trigger
13475
- setup screens. Scope: `crm`."
13647
+ parameters:
13648
+ - name: key
13649
+ in: path
13650
+ required: true
13651
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13652
+ schema:
13653
+ type: string
13654
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13655
+ - name: q
13656
+ in: query
13657
+ required: false
13658
+ description: Free-text search.
13659
+ schema:
13660
+ type: string
13661
+ maxLength: 100
13662
+ - name: filters
13663
+ in: query
13664
+ required: false
13665
+ description: 'Lists-engine filter, JSON: `{"match":"and|or","conditions":[{"field":"cf:status","op":"in","value":["active"]}]}`. GET
13666
+ …/schema lists the fields and operators.'
13667
+ schema:
13668
+ type: string
13669
+ - name: view
13670
+ in: query
13671
+ required: false
13672
+ description: A saved view id (its filters / sort apply), or `all`.
13673
+ schema:
13674
+ type: string
13675
+ - name: sort
13676
+ in: query
13677
+ required: false
13678
+ description: Sort key (see …/schema `sorts`), e.g. `cf:budget`.
13679
+ schema:
13680
+ type: string
13681
+ - name: dir
13682
+ in: query
13683
+ required: false
13684
+ description: Sort direction.
13685
+ schema:
13686
+ type: string
13687
+ enum:
13688
+ - asc
13689
+ - desc
13690
+ - name: page
13691
+ in: query
13692
+ required: false
13693
+ description: Page number.
13694
+ schema:
13695
+ type: integer
13696
+ minimum: 1
13697
+ default: 1
13698
+ - name: per_page
13699
+ in: query
13700
+ required: false
13701
+ description: Rows per page (max 100).
13702
+ schema:
13703
+ type: integer
13704
+ minimum: 1
13705
+ maximum: 100
13706
+ default: 25
13707
+ - name: updated_since
13708
+ in: query
13709
+ required: false
13710
+ description: Only records changed at or after this ISO 8601 time (polling triggers).
13711
+ schema:
13712
+ type: string
13713
+ format: date-time
13714
+ responses:
13715
+ "200":
13716
+ description: One page.
13717
+ content:
13718
+ application/json:
13719
+ schema:
13720
+ type: object
13721
+ required:
13722
+ - success
13723
+ - data
13724
+ properties:
13725
+ success:
13726
+ const: true
13727
+ data:
13728
+ type: array
13729
+ items:
13730
+ $ref: "#/components/schemas/CrmCustomRecord"
13731
+ meta:
13732
+ $ref: "#/components/schemas/CrmListMeta"
13733
+ "401":
13734
+ $ref: "#/components/responses/ZapierUnauthorized"
13735
+ "403":
13736
+ $ref: "#/components/responses/CrmForbidden"
13737
+ "404":
13738
+ $ref: "#/components/responses/CrmNotFound"
13739
+ "422":
13740
+ $ref: "#/components/responses/CrmValidationFailed"
13741
+ "429":
13742
+ $ref: "#/components/responses/TooManyRequests"
13743
+ post:
13744
+ operationId: crmCreateCustomRecord
13745
+ tags:
13746
+ - CRM
13747
+ summary: Create a custom record
13748
+ description: "Creates a record. `values` is keyed by field key; the title field and required fields must be filled; formula and rollup fields are computed. Relation fields take a record id (a list of ids when the field allows many). Validated like the panel; fires the record created automations. Scope: `crm`."
13749
+ security:
13750
+ - zapierApiKey: []
13751
+ parameters:
13752
+ - name: key
13753
+ in: path
13754
+ required: true
13755
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13756
+ schema:
13757
+ type: string
13758
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13759
+ requestBody:
13760
+ required: true
13761
+ content:
13762
+ application/json:
13763
+ schema:
13764
+ $ref: "#/components/schemas/CrmCustomRecordInput"
13765
+ responses:
13766
+ "201":
13767
+ description: Created.
13768
+ content:
13769
+ application/json:
13770
+ schema:
13771
+ type: object
13772
+ required:
13773
+ - success
13774
+ - data
13775
+ properties:
13776
+ success:
13777
+ const: true
13778
+ data:
13779
+ $ref: "#/components/schemas/CrmCustomRecord"
13780
+ "401":
13781
+ $ref: "#/components/responses/ZapierUnauthorized"
13782
+ "403":
13783
+ $ref: "#/components/responses/CrmForbidden"
13784
+ "404":
13785
+ $ref: "#/components/responses/CrmNotFound"
13786
+ "422":
13787
+ $ref: "#/components/responses/CrmValidationFailed"
13788
+ "429":
13789
+ $ref: "#/components/responses/TooManyRequests"
13790
+ /v1/crm/objects/{key}/records/search:
13791
+ x-letsbot-surface: zapier
13792
+ servers:
13793
+ - url: https://{workspace}.letsbot.net/api
13794
+ description: The workspace's own subdomain. The CRM API lives under /v1/crm.
13795
+ variables:
13796
+ workspace:
13797
+ default: your-workspace
13798
+ description: The workspace subdomain.
13799
+ get:
13800
+ operationId: crmSearchCustomRecords
13801
+ tags:
13802
+ - CRM
13803
+ summary: Find custom records
13804
+ description: "Records whose title (or a sortable text field) contains `q`, most recently updated first. Scope: `crm`."
13805
+ security:
13806
+ - zapierApiKey: []
13807
+ parameters:
13808
+ - name: key
13809
+ in: path
13810
+ required: true
13811
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13812
+ schema:
13813
+ type: string
13814
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13815
+ - name: q
13816
+ in: query
13817
+ required: false
13818
+ description: Text to find.
13819
+ schema:
13820
+ type: string
13821
+ maxLength: 100
13822
+ - name: per_page
13823
+ in: query
13824
+ required: false
13825
+ description: Maximum records (max 100).
13826
+ schema:
13827
+ type: integer
13828
+ minimum: 1
13829
+ maximum: 100
13830
+ default: 25
13831
+ responses:
13832
+ "200":
13833
+ description: OK
13834
+ content:
13835
+ application/json:
13836
+ schema:
13837
+ type: object
13838
+ required:
13839
+ - success
13840
+ - data
13841
+ properties:
13842
+ success:
13843
+ const: true
13844
+ data:
13845
+ type: array
13846
+ items:
13847
+ $ref: "#/components/schemas/CrmCustomRecord"
13848
+ "401":
13849
+ $ref: "#/components/responses/ZapierUnauthorized"
13850
+ "403":
13851
+ $ref: "#/components/responses/CrmForbidden"
13852
+ "404":
13853
+ $ref: "#/components/responses/CrmNotFound"
13854
+ "429":
13855
+ $ref: "#/components/responses/TooManyRequests"
13856
+ /v1/crm/objects/{key}/records/{id}:
13857
+ x-letsbot-surface: zapier
13858
+ servers:
13859
+ - url: https://{workspace}.letsbot.net/api
13860
+ description: The workspace's own subdomain. The CRM API lives under /v1/crm.
13861
+ variables:
13862
+ workspace:
13863
+ default: your-workspace
13864
+ description: The workspace subdomain.
13865
+ get:
13866
+ operationId: crmGetCustomRecord
13867
+ tags:
13868
+ - CRM
13869
+ summary: Get a custom record
13870
+ description: "One record with its field values. Scope: `crm`."
13871
+ security:
13872
+ - zapierApiKey: []
13873
+ parameters:
13874
+ - name: key
13875
+ in: path
13876
+ required: true
13877
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13878
+ schema:
13879
+ type: string
13880
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13881
+ - name: id
13882
+ in: path
13883
+ required: true
13884
+ description: The record id.
13885
+ schema:
13886
+ type: integer
13887
+ responses:
13888
+ "200":
13889
+ description: OK
13890
+ content:
13891
+ application/json:
13892
+ schema:
13893
+ type: object
13894
+ required:
13895
+ - success
13896
+ - data
13897
+ properties:
13898
+ success:
13899
+ const: true
13900
+ data:
13901
+ $ref: "#/components/schemas/CrmCustomRecord"
13902
+ "401":
13903
+ $ref: "#/components/responses/ZapierUnauthorized"
13904
+ "403":
13905
+ $ref: "#/components/responses/CrmForbidden"
13906
+ "404":
13907
+ $ref: "#/components/responses/CrmNotFound"
13908
+ "429":
13909
+ $ref: "#/components/responses/TooManyRequests"
13910
+ patch:
13911
+ operationId: crmUpdateCustomRecord
13912
+ tags:
13913
+ - CRM
13914
+ summary: Update a custom record
13915
+ description: "Only the values sent change (send `null` to clear one). Changes are kept in the field history with source `api` and fire the record updated automations. Scope: `crm`."
13916
+ security:
13917
+ - zapierApiKey: []
13918
+ parameters:
13919
+ - name: key
13920
+ in: path
13921
+ required: true
13922
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13923
+ schema:
13924
+ type: string
13925
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13926
+ - name: id
13927
+ in: path
13928
+ required: true
13929
+ description: The record id.
13930
+ schema:
13931
+ type: integer
13932
+ requestBody:
13933
+ required: true
13934
+ content:
13935
+ application/json:
13936
+ schema:
13937
+ $ref: "#/components/schemas/CrmCustomRecordInput"
13938
+ responses:
13939
+ "200":
13940
+ description: OK
13941
+ content:
13942
+ application/json:
13943
+ schema:
13944
+ type: object
13945
+ required:
13946
+ - success
13947
+ - data
13948
+ properties:
13949
+ success:
13950
+ const: true
13951
+ data:
13952
+ $ref: "#/components/schemas/CrmCustomRecord"
13953
+ "401":
13954
+ $ref: "#/components/responses/ZapierUnauthorized"
13955
+ "403":
13956
+ $ref: "#/components/responses/CrmForbidden"
13957
+ "404":
13958
+ $ref: "#/components/responses/CrmNotFound"
13959
+ "422":
13960
+ $ref: "#/components/responses/CrmValidationFailed"
13961
+ "429":
13962
+ $ref: "#/components/responses/TooManyRequests"
13963
+ delete:
13964
+ operationId: crmDeleteCustomRecord
13965
+ tags:
13966
+ - CRM
13967
+ summary: Delete a custom record
13968
+ description: "Moves the record to the trash. Scope: `crm`."
13969
+ security:
13970
+ - zapierApiKey: []
13971
+ parameters:
13972
+ - name: key
13973
+ in: path
13974
+ required: true
13975
+ description: The custom object key, e.g. `co_projects` (GET /v1/crm/objects).
13976
+ schema:
13977
+ type: string
13978
+ pattern: ^co_[a-z][a-z0-9_]{1,12}$
13979
+ - name: id
13980
+ in: path
13981
+ required: true
13982
+ description: The record id.
13983
+ schema:
13984
+ type: integer
13985
+ responses:
13986
+ "200":
13987
+ description: Deleted.
13988
+ content:
13989
+ application/json:
13990
+ schema:
13991
+ type: object
13992
+ required:
13993
+ - success
13994
+ - data
13995
+ properties:
13996
+ success:
13997
+ const: true
13998
+ data:
13999
+ type: object
14000
+ required:
14001
+ - id
14002
+ - deleted
14003
+ properties:
14004
+ id:
14005
+ type: integer
14006
+ deleted:
14007
+ const: true
14008
+ "401":
14009
+ $ref: "#/components/responses/ZapierUnauthorized"
14010
+ "403":
14011
+ $ref: "#/components/responses/CrmForbidden"
14012
+ "404":
14013
+ $ref: "#/components/responses/CrmNotFound"
14014
+ "429":
14015
+ $ref: "#/components/responses/TooManyRequests"
14016
+ /v1/crm/hooks:
14017
+ x-letsbot-surface: zapier
14018
+ servers: *a2
14019
+ get:
14020
+ operationId: crmListHooks
14021
+ tags:
14022
+ - CRM
14023
+ summary: List API webhook subscriptions
14024
+ description: "Subscriptions created through the API (panel-made ones are managed in the panel). Secrets are never
14025
+ returned again. Scope: `crm`."
14026
+ security:
14027
+ - zapierApiKey: []
14028
+ responses:
14029
+ "200":
14030
+ description: OK
14031
+ content:
14032
+ application/json:
14033
+ schema:
14034
+ type: object
14035
+ required:
14036
+ - success
14037
+ - data
14038
+ properties:
14039
+ success:
14040
+ const: true
14041
+ data:
14042
+ type: array
14043
+ items:
14044
+ $ref: "#/components/schemas/CrmWebhookSubscription"
14045
+ "401":
14046
+ $ref: "#/components/responses/ZapierUnauthorized"
14047
+ "403":
14048
+ $ref: "#/components/responses/CrmForbidden"
14049
+ "404":
14050
+ $ref: "#/components/responses/CrmNotFound"
14051
+ "429":
14052
+ $ref: "#/components/responses/TooManyRequests"
14053
+ post:
14054
+ operationId: crmSubscribeHook
14055
+ tags:
14056
+ - CRM
14057
+ summary: Subscribe a webhook (REST hook)
14058
+ description: 'Zapier / Make / n8n REST-hook subscribe. Accepts `target_url` or `url`, and `event` or `events`. The
14059
+ answer carries the signing `secret` ONCE. Deliveries are POSTed as CrmWebhookEvent with `X-LetsBot-Signature:
14060
+ t=<unix>,v1=<hex HMAC-SHA256 of "t.body">`, `X-LetsBot-Event` and `X-LetsBot-Delivery`; failed deliveries are
14061
+ retried with backoff (1 min, 5 min, 30 min, 2 h, 6 h); after 5 deliveries in a row fail the subscription is
14062
+ switched off, and an HTTP 410 answer switches it off at once. Scope: `crm`.'
14063
+ security:
14064
+ - zapierApiKey: []
14065
+ requestBody:
14066
+ required: true
14067
+ content:
14068
+ application/json:
14069
+ schema:
14070
+ type: object
14071
+ properties:
14072
+ target_url:
14073
+ type: string
14074
+ format: uri
14075
+ url:
14076
+ type: string
14077
+ format: uri
14078
+ event:
14079
+ $ref: "#/components/schemas/CrmWebhookEventName"
14080
+ events:
14081
+ type: array
14082
+ items:
14083
+ $ref: "#/components/schemas/CrmWebhookEventName"
14084
+ source:
14085
+ type: string
14086
+ enum:
14087
+ - zapier
14088
+ - make
14089
+ - n8n
14090
+ - api
14091
+ description:
14092
+ type:
14093
+ - string
14094
+ - "null"
14095
+ responses:
14096
+ "201":
14097
+ description: Subscribed.
14098
+ content:
14099
+ application/json:
14100
+ schema:
14101
+ type: object
14102
+ required:
14103
+ - success
14104
+ - data
14105
+ properties:
14106
+ success:
14107
+ const: true
14108
+ data:
14109
+ allOf:
14110
+ - $ref: "#/components/schemas/CrmWebhookSubscription"
14111
+ - type: object
14112
+ required:
14113
+ - secret
14114
+ properties:
14115
+ secret:
14116
+ type: string
14117
+ "401":
14118
+ $ref: "#/components/responses/ZapierUnauthorized"
14119
+ "403":
14120
+ $ref: "#/components/responses/CrmForbidden"
14121
+ "404":
14122
+ $ref: "#/components/responses/CrmNotFound"
14123
+ "422": *a1
14124
+ "429":
14125
+ $ref: "#/components/responses/TooManyRequests"
14126
+ /v1/crm/hooks/events:
14127
+ x-letsbot-surface: zapier
14128
+ servers: *a2
14129
+ get:
14130
+ operationId: crmListHookEvents
14131
+ tags:
14132
+ - CRM
14133
+ summary: List webhook events
14134
+ description: "The event catalogue. Scope: `crm`."
14135
+ security:
14136
+ - zapierApiKey: []
14137
+ responses:
14138
+ "200":
14139
+ description: OK
14140
+ content:
14141
+ application/json:
14142
+ schema:
14143
+ type: object
14144
+ required:
14145
+ - success
14146
+ - data
14147
+ properties:
14148
+ success:
14149
+ const: true
14150
+ data:
14151
+ type: array
14152
+ items:
14153
+ type: object
14154
+ required:
14155
+ - event
14156
+ - object
14157
+ properties:
14158
+ event:
14159
+ $ref: "#/components/schemas/CrmWebhookEventName"
14160
+ object:
14161
+ type: string
14162
+ "401":
14163
+ $ref: "#/components/responses/ZapierUnauthorized"
14164
+ "403":
14165
+ $ref: "#/components/responses/CrmForbidden"
14166
+ "404":
14167
+ $ref: "#/components/responses/CrmNotFound"
14168
+ "429":
14169
+ $ref: "#/components/responses/TooManyRequests"
14170
+ /v1/crm/hooks/sample:
14171
+ x-letsbot-surface: zapier
14172
+ servers: *a2
14173
+ get:
14174
+ operationId: crmHookSample
14175
+ tags:
14176
+ - CRM
14177
+ summary: Sample webhook payload
14178
+ description: "One sample event built from the newest record of that object (empty when there is none) — for trigger
14179
+ setup screens. Scope: `crm`."
13476
14180
  security:
13477
14181
  - zapierApiKey: []
13478
14182
  parameters:
@@ -13909,6 +14613,23 @@ components:
13909
14613
  type:
13910
14614
  - string
13911
14615
  - 'null'
14616
+ whatsapp_bsuid:
14617
+ type:
14618
+ - string
14619
+ - 'null'
14620
+ description: Meta's business-scoped user ID for a customer who hides their number behind a WhatsApp username
14621
+ (e.g. `EG.2288384708632117`). Not a phone number. Sent only for workspaces with WhatsApp username support
14622
+ switched on.
14623
+ whatsapp_username:
14624
+ type:
14625
+ - string
14626
+ - 'null'
14627
+ description: The customer's WhatsApp @username, without the `@`. Display only. Sent only for workspaces with
14628
+ WhatsApp username support switched on.
14629
+ phone_available:
14630
+ type: boolean
14631
+ description: '`false` when the customer keeps their number private: `phone` then holds an identity, so do not
14632
+ SMS, call or store it as a number. Sent only for workspaces with WhatsApp username support switched on.'
13912
14633
  labels:
13913
14634
  type: array
13914
14635
  items:
@@ -14733,6 +15454,7 @@ components:
14733
15454
  - missing_scope
14734
15455
  - validation_failed
14735
15456
  - already_exists
15457
+ - possible_duplicate
14736
15458
  - conflict
14737
15459
  - forbidden
14738
15460
  - unprocessable
@@ -14745,6 +15467,27 @@ components:
14745
15467
  type: string
14746
15468
  data:
14747
15469
  description: "On `already_exists`: the existing record."
15470
+ existing_id:
15471
+ type: integer
15472
+ description: "On `already_exists` / `possible_duplicate`: the id of the record to update instead."
15473
+ duplicates:
15474
+ type: array
15475
+ description: "On `possible_duplicate`: the likely duplicates, best match first. Repeat the request with
15476
+ `?allow_duplicate=1` to create the record anyway."
15477
+ items:
15478
+ type: object
15479
+ required:
15480
+ - id
15481
+ - reason
15482
+ properties:
15483
+ id:
15484
+ type: integer
15485
+ reason:
15486
+ type: string
15487
+ description: "What matched: `phone`, `bsuid`, `email` (contacts) or `domain`, `company_name` (companies)."
15488
+ confidence:
15489
+ type: integer
15490
+ description: 0–100.
14748
15491
  CrmContact:
14749
15492
  type: object
14750
15493
  required:
@@ -14805,6 +15548,23 @@ components:
14805
15548
  updated_at: *a2
14806
15549
  url:
14807
15550
  type: string
15551
+ whatsapp_bsuid:
15552
+ type:
15553
+ - string
15554
+ - "null"
15555
+ description: Meta's business-scoped user ID for a customer who hides their number behind a WhatsApp username
15556
+ (e.g. `EG.2288384708632117`). Not a phone number. Sent only for workspaces with WhatsApp username support
15557
+ switched on.
15558
+ whatsapp_username:
15559
+ type:
15560
+ - string
15561
+ - "null"
15562
+ description: The customer's WhatsApp @username, without the `@`. Display only. Sent only for workspaces with
15563
+ WhatsApp username support switched on.
15564
+ phone_available:
15565
+ type: boolean
15566
+ description: "`false` when the customer keeps their number private: `phone` then holds an identity, so do not
15567
+ SMS, call or store it as a number. Sent only for workspaces with WhatsApp username support switched on."
14808
15568
  CrmCompany:
14809
15569
  type: object
14810
15570
  required:
@@ -15210,6 +15970,134 @@ components:
15210
15970
  updated_at: *a2
15211
15971
  url:
15212
15972
  type: string
15973
+ CrmCustomObject:
15974
+ type: object
15975
+ description: A merchant-defined CRM object (custom objects).
15976
+ required:
15977
+ - key
15978
+ - label_singular
15979
+ - label_plural
15980
+ - primary_field
15981
+ - fields
15982
+ properties:
15983
+ key:
15984
+ type: string
15985
+ description: Immutable object key, `co_<slug>`.
15986
+ examples:
15987
+ - co_projects
15988
+ label_singular:
15989
+ type: object
15990
+ description: Names by language (`ar`, `en`).
15991
+ additionalProperties:
15992
+ type: string
15993
+ label_plural:
15994
+ type: object
15995
+ additionalProperties:
15996
+ type: string
15997
+ primary_field:
15998
+ type: string
15999
+ description: Key of the field used as the record title.
16000
+ fields:
16001
+ type: array
16002
+ items:
16003
+ type: object
16004
+ required:
16005
+ - key
16006
+ - label
16007
+ - type
16008
+ - required
16009
+ - read_only
16010
+ properties:
16011
+ key:
16012
+ type: string
16013
+ label:
16014
+ type: string
16015
+ type:
16016
+ type: string
16017
+ enum:
16018
+ - text
16019
+ - textarea
16020
+ - number
16021
+ - currency
16022
+ - date
16023
+ - datetime
16024
+ - select
16025
+ - multiselect
16026
+ - boolean
16027
+ - url
16028
+ - email
16029
+ - phone
16030
+ - user
16031
+ - relation
16032
+ - formula
16033
+ - rollup
16034
+ - file
16035
+ required:
16036
+ type: boolean
16037
+ read_only:
16038
+ type: boolean
16039
+ description: Formula and rollup fields are computed by LetsBot.
16040
+ options:
16041
+ type:
16042
+ - array
16043
+ - "null"
16044
+ description: Choices of a `select` / `multiselect` field (send the `value`).
16045
+ items:
16046
+ type: object
16047
+ properties:
16048
+ value:
16049
+ type: string
16050
+ label:
16051
+ type: string
16052
+ settings:
16053
+ type: object
16054
+ additionalProperties: true
16055
+ description: "Type settings, e.g. `{target: company, many: true}` for a relation, `{currency: SAR}` for a currency."
16056
+ CrmCustomRecord:
16057
+ type: object
16058
+ required:
16059
+ - id
16060
+ - object
16061
+ - title
16062
+ - values
16063
+ properties:
16064
+ id:
16065
+ type: integer
16066
+ object:
16067
+ type: string
16068
+ description: The object key.
16069
+ title:
16070
+ type:
16071
+ - string
16072
+ - "null"
16073
+ description: The title field's value.
16074
+ owner_user_id:
16075
+ type:
16076
+ - integer
16077
+ - "null"
16078
+ values:
16079
+ type: object
16080
+ additionalProperties: true
16081
+ description: Field key → value.
16082
+ created_at:
16083
+ type: string
16084
+ format: date-time
16085
+ updated_at:
16086
+ type: string
16087
+ format: date-time
16088
+ CrmCustomRecordInput:
16089
+ type: object
16090
+ properties:
16091
+ values:
16092
+ type: object
16093
+ additionalProperties: true
16094
+ description: Field key → value. Dropdowns take the option value, dates YYYY-MM-DD, relation fields a record id (a
16095
+ list of ids when the field allows many), user fields a team member id, file fields uploaded file ids.
16096
+ owner_user_id:
16097
+ type:
16098
+ - integer
16099
+ - "null"
16100
+ description: Team member who owns the record.
15213
16101
  CrmProduct:
15214
16102
  type: object
15215
16103
  required:
@@ -15269,6 +16157,12 @@ components:
15269
16157
  - quote.sent
15270
16158
  - quote.viewed
15271
16159
  - quote.accepted
16160
+ - quote.signed
16161
+ - quote.paid
16162
+ - invoice.created
16163
+ - form.submitted
16164
+ - deal.assigned
16165
+ - health.at_risk
15272
16166
  CrmWebhookSubscription:
15273
16167
  type: object
15274
16168
  required:
@@ -15360,6 +16254,105 @@ components:
15360
16254
  type:
15361
16255
  - string
15362
16256
  - "null"
16257
+ invoice:
16258
+ type: object
16259
+ description: "invoice.created only (`data` is the quote): the invoice made from the quote."
16260
+ properties:
16261
+ id:
16262
+ type: integer
16263
+ kind:
16264
+ type: string
16265
+ enum:
16266
+ - erp
16267
+ - simplified
16268
+ number:
16269
+ type:
16270
+ - string
16271
+ - "null"
16272
+ erp_invoice_id:
16273
+ type:
16274
+ - integer
16275
+ - "null"
16276
+ currency:
16277
+ type: string
16278
+ subtotal:
16279
+ type: string
16280
+ discount_total:
16281
+ type: string
16282
+ tax_total:
16283
+ type: string
16284
+ total:
16285
+ type: string
16286
+ issue_date:
16287
+ type:
16288
+ - string
16289
+ - "null"
16290
+ format: date
16291
+ uuid:
16292
+ type: string
16293
+ form:
16294
+ type: object
16295
+ description: "form.submitted only (`data` is the contact): which form and what was answered."
16296
+ properties:
16297
+ source:
16298
+ type: string
16299
+ enum:
16300
+ - web_form
16301
+ - typeform
16302
+ - google_forms
16303
+ form_id:
16304
+ type:
16305
+ - integer
16306
+ - "null"
16307
+ form_name:
16308
+ type:
16309
+ - string
16310
+ - "null"
16311
+ submission_id:
16312
+ type:
16313
+ - integer
16314
+ - "null"
16315
+ deal_id:
16316
+ type:
16317
+ - integer
16318
+ - "null"
16319
+ contact_created:
16320
+ type: boolean
16321
+ answers:
16322
+ type: array
16323
+ items:
16324
+ type: object
16325
+ properties:
16326
+ label:
16327
+ type: string
16328
+ value:
16329
+ type: string
16330
+ assignment:
16331
+ type: object
16332
+ description: "deal.assigned only: the new owner and the one before (null for a new deal)."
16333
+ properties:
16334
+ owner_user_id:
16335
+ type: integer
16336
+ previous_owner_user_id:
16337
+ type:
16338
+ - integer
16339
+ - "null"
16340
+ health:
16341
+ type: object
16342
+ description: "health.at_risk only (`object` is contact or company): the health score and why."
16343
+ properties:
16344
+ score:
16345
+ type:
16346
+ - integer
16347
+ - "null"
16348
+ previous:
16349
+ type:
16350
+ - string
16351
+ - "null"
16352
+ reasons:
16353
+ type: array
16354
+ items:
16355
+ type: string
15363
16356
  responses:
15364
16357
  LegacyValidationFailure:
15365
16358
  description: 'Validation failed (historic contract, the default: HTTP 202, nothing was done). With
@@ -15515,7 +16508,8 @@ components:
15515
16508
  schema:
15516
16509
  $ref: "#/components/schemas/CrmError"
15517
16510
  CrmConflict:
15518
- description: Conflict (`already_exists` with the existing record in `data`, or `conflict`).
16511
+ description: "Conflict: `already_exists` (the existing record in `data`), `possible_duplicate` (a likely duplicate
16512
+ — `existing_id` + `duplicates`; repeat with `?allow_duplicate=1` to create anyway) or `conflict`."
15519
16513
  content:
15520
16514
  application/json:
15521
16515
  schema: