{"openapi":"3.1.0","info":{"title":"Grovia API","version":"1.0.0","description":"Read and write your Grovia leads, clients, invoices and payments, and receive webhooks when they change. Create a key in Grovia → Settings → API & Webhooks. Each key belongs to one company account and only sees that account's data.","contact":{"name":"Grovia support","url":"https://groviaos.com/contact"}},"servers":[{"url":"https://groviaos.com/api/v1"}],"security":[{"bearer":[]}],"tags":[{"name":"Account"},{"name":"Leads"},{"name":"Clients"},{"name":"Invoices"},{"name":"Payments"},{"name":"Webhooks"},{"name":"Tally"}],"paths":{"/me":{"get":{"tags":["Account"],"operationId":"getMe","summary":"Check a key","description":"Which account the key belongs to and its scopes. Works with any valid key.","responses":{"200":{"description":"The key's account and scopes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/leads":{"get":{"tags":["Leads"],"operationId":"listLeads","summary":"List leads","description":"Newest first. Scope: leads:read.","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["new","contacted","qualified","proposal","proposal_sent","negotiation","won","lost","spam"]}},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only rows updated at or after this ISO time."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (1–100)."},{"name":"starting_after","in":"query","schema":{"type":"string"},"description":"The next_cursor from the previous page."}],"responses":{"200":{"description":"A page of leads.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}},"400":{"description":"A bad filter or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Leads"],"operationId":"createLead","summary":"Create a lead","description":"Goes through the same path as every other enquiry: a repeat from the same phone or email within 30 days is added to the open lead (200 + duplicate:true) instead of making a twin. Send external_id to make retries safe. Scope: leads:write.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadCreate"}}}},"responses":{"200":{"description":"Added to this person's open lead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadWithDuplicate"}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadWithDuplicate"}}}},"400":{"description":"The body is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"No usable phone or email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/leads/{id}":{"get":{"tags":["Leads"],"operationId":"getLead","summary":"Get a lead","description":"Scope: leads:read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The lead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lead"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No lead with that id in this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Leads"],"operationId":"updateLead","summary":"Update a lead","description":"Change stage, notes, value or owner. Moving to won stamps won_at and fires lead.won. Scope: leads:write.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadUpdate"}}}},"responses":{"200":{"description":"The updated lead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lead"}}}},"400":{"description":"The body is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients":{"get":{"tags":["Clients"],"operationId":"listClients","summary":"List clients","description":"Newest first. Scope: clients:read.","parameters":[{"name":"email","in":"query","schema":{"type":"string"},"description":"Exact email (any case)."},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only rows updated at or after this ISO time."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (1–100)."},{"name":"starting_after","in":"query","schema":{"type":"string"},"description":"The next_cursor from the previous page."}],"responses":{"200":{"description":"A page of clients.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Client"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}},"400":{"description":"A bad filter or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Clients"],"operationId":"createClient","summary":"Create (or find) a client","description":"One client per email per account: if the email exists you get that client back with duplicate:true. Scope: clients:write.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientCreate"}}}},"responses":{"200":{"description":"Already existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientWithDuplicate"}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Client"}}}},"400":{"description":"The body is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients/{id}":{"get":{"tags":["Clients"],"operationId":"getClient","summary":"Get a client","description":"Scope: clients:read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The client.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Client"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices":{"get":{"tags":["Invoices"],"operationId":"listInvoices","summary":"List invoices","description":"Newest first. Scope: invoices:read.","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","sent","paid","partial","cancelled","overdue"]}},{"name":"client_id","in":"query","schema":{"type":"string"}},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only rows updated at or after this ISO time."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (1–100)."},{"name":"starting_after","in":"query","schema":{"type":"string"},"description":"The next_cursor from the previous page."}],"responses":{"200":{"description":"A page of invoices.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}},"400":{"description":"A bad filter or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices/{id}":{"get":{"tags":["Invoices"],"operationId":"getInvoice","summary":"Get an invoice","description":"Scope: invoices:read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The invoice.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payments":{"get":{"tags":["Payments"],"operationId":"listPayments","summary":"List payments received","description":"Newest first. Scope: invoices:read.","parameters":[{"name":"invoice_id","in":"query","schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only rows paid at or after this ISO time."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (1–100)."},{"name":"starting_after","in":"query","schema":{"type":"string"},"description":"The next_cursor from the previous page."}],"responses":{"200":{"description":"A page of payments.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Payment"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}},"400":{"description":"A bad filter or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tally/export":{"get":{"tags":["Tally"],"operationId":"exportTally","summary":"Export TallyPrime XML","description":"The same file as Grovia → Tally Export, for pushing into TallyPrime (used by the Grovia Tally Connector). Indian GST accounts only. Scope: accounting:read. At most 366 days per request.","parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["masters","sales","purchases","receipts","payments","credit-notes","contras","journals","debit-notes","advances"]}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"First day (Indian date)."},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Last day, included."}],"responses":{"200":{"description":"TallyPrime import XML.","content":{"text/xml":{"schema":{"type":"string"}}}},"400":{"description":"Bad type or dates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"operationId":"listWebhooks","summary":"List webhooks","description":"This account's webhooks, including ones switched off. Secrets are never returned. Any valid key.","responses":{"200":{"description":"The webhooks.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"operationId":"createWebhook","summary":"Subscribe a webhook","description":"For automation platforms (REST hooks): register an https address for some events. The key needs the read scope of each event's data (lead.* → leads:read, client.created → clients:read, invoice.* and payment.received → invoices:read). The signing secret is returned once. Up to 25 webhooks can be switched on per account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}}},"responses":{"201":{"description":"Subscribed. Store the secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookWithSecret"}}}},"400":{"description":"Bad address or events, or the limit is reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"get":{"tags":["Webhooks"],"operationId":"getWebhook","summary":"Get a webhook","description":"Any valid key.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The webhook.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Webhooks"],"operationId":"deleteWebhook","summary":"Unsubscribe a webhook","description":"Switches the webhook off; its delivery history is kept. Calling it again is harmless.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Missing or wrong API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have the scope this needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 requests a minute for this key. Wait for Retry-After seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"lead.created":{"post":{"summary":"A new lead or enquiry arrives","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"lead.created"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"lead.updated":{"post":{"summary":"A lead's stage or owner changes","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"lead.updated"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"lead.won":{"post":{"summary":"A lead is marked won","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"lead.won"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"client.created":{"post":{"summary":"A client is added","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"client.created"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"invoice.created":{"post":{"summary":"An invoice is created","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"invoice.created"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"invoice.paid":{"post":{"summary":"An invoice is paid in full","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"invoice.paid"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}},"payment.received":{"post":{"summary":"A payment is recorded against an invoice","description":"Grovia POSTs JSON to your URL. Check the Grovia-Signature header (t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\" with your signing secret>) and reply 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 30, 120, 360, 720 and 1440 minutes.","parameters":[{"name":"Grovia-Event","in":"header","schema":{"type":"string","const":"payment.received"}},{"name":"Grovia-Delivery","in":"header","schema":{"type":"string"},"description":"Unique per delivery; use it to ignore repeats."},{"name":"Grovia-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received."}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Authorization: Bearer gro_live_…  (X-Api-Key: gro_live_… also works)"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"Me":{"type":"object","properties":{"object":{"type":"string","const":"api_key"},"account":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"scopes":{"type":"array","items":{"type":"string","enum":["leads:read","leads:write","clients:read","clients:write","invoices:read","accounting:read"]}}}},"Lead":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"lead"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"subject":{"type":["string","null"]},"message":{"type":"string"},"source":{"type":["string","null"]},"channel":{"type":["string","null"],"description":"How it arrived: website, whatsapp, indiamart, api …"},"status":{"type":"string","enum":["new","contacted","qualified","proposal","proposal_sent","negotiation","won","lost","spam"]},"expected_value":{"type":["number","null"]},"client_id":{"type":["string","null"]},"owner_user_id":{"type":["string","null"]},"won_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"LeadWithDuplicate":{"allOf":[{"$ref":"#/components/schemas/Lead"},{"type":"object","properties":{"duplicate":{"type":"boolean"}}}]},"LeadCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":200},"phone":{"type":"string","maxLength":30},"message":{"type":"string","maxLength":5000},"source":{"type":"string","maxLength":120,"description":"Shown on the lead, e.g. \"Facebook form\"."},"external_id":{"type":"string","maxLength":120,"description":"Your id for this enquiry. Sending the same one twice returns the first lead."}},"description":"Send at least a phone or an email."},"LeadUpdate":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","enum":["new","contacted","qualified","proposal","proposal_sent","negotiation","won","lost","spam"]},"notes":{"type":["string","null"],"maxLength":10000},"expected_value":{"type":["number","null"]},"owner_user_id":{"type":["string","null"],"description":"A member of this account; null clears it."}}},"Client":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"client"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"company":{"type":["string","null"]},"gstin":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ClientWithDuplicate":{"allOf":[{"$ref":"#/components/schemas/Client"},{"type":"object","properties":{"duplicate":{"type":"boolean"}}}]},"ClientCreate":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string","maxLength":200},"email":{"type":"string","format":"email"},"phone":{"type":"string","maxLength":30},"company":{"type":"string"},"gstin":{"type":"string","pattern":"^[0-9A-Z]{15}$"},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"country":{"type":"string"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"invoice"},"number":{"type":"string"},"status":{"type":"string","enum":["draft","sent","paid","partial","cancelled","overdue"]},"client_id":{"type":"string"},"currency":{"type":"string"},"invoice_date":{"type":"string","format":"date-time"},"due_date":{"type":["string","null"],"format":"date-time"},"paid_at":{"type":["string","null"],"format":"date-time"},"taxable_value":{"type":"number"},"tax":{"type":"number"},"round_off":{"type":"number"},"total":{"type":"number"},"amount_paid":{"type":"number"},"tds_deducted":{"type":"number","description":"TDS the customer deducted; it settles the invoice like cash."},"balance_due":{"type":"number","description":"total − amount_paid − tds_deducted, never below 0."},"lines":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string"},"quantity":{"type":"number"},"unit_price":{"type":"number"},"gst_rate":{"type":"number"},"discount_percent":{"type":["number","null"]},"discount_amount":{"type":["number","null"]}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Payment":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"payment"},"invoice_id":{"type":"string"},"amount":{"type":"number"},"tds_amount":{"type":"number"},"method":{"type":"string"},"reference":{"type":["string","null"]},"paid_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"webhook"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.updated","lead.won","client.created","invoice.created","invoice.paid","payment.received"]}},"enabled":{"type":"boolean"},"description":{"type":["string","null"]},"disabled_reason":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"WebhookWithSecret":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"whsec_… — shown only in this response."}}}]},"WebhookCreate":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"A public https address."},"events":{"type":"array","minItems":1,"items":{"type":"string","enum":["lead.created","lead.updated","lead.won","client.created","invoice.created","invoice.paid","payment.received"]}},"description":{"type":"string","maxLength":200}}},"WebhookEvent":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["lead.created","lead.updated","lead.won","client.created","invoice.created","invoice.paid","payment.received"]},"created_at":{"type":"string","format":"date-time"},"test":{"type":"boolean","description":"Present and true only on a test sent from Settings → API & Webhooks."},"data":{"oneOf":[{"$ref":"#/components/schemas/Lead"},{"$ref":"#/components/schemas/Client"},{"$ref":"#/components/schemas/Invoice"},{"$ref":"#/components/schemas/Payment"}],"description":"The lead, client, invoice or payment, in the same shape the API returns."}}}}}}