Skip to content

Grant credits

POST /api/v2/grants

Grants credits to a contact after a payment event. Call this when a purchase is confirmed in your own checkout. Requires the grant scope. Uses the common headers and is idempotent via request_id.

FieldTypeRequiredNotes
location_idstringyesMust match the token’s location
request_idstringyesIdempotency key
external_payment_idstringyesYour payment reference; deduplicates grants
external_contact_idstringyes*Provider-neutral contact id for non-GHL systems. Send this or ghl_contact_idexternal_contact_id wins if both are present
ghl_contact_idstringyes*The GoHighLevel contact id. Interchangeable with external_contact_id
product_config_idstringyesThe Kotally product config to apply
providerstringnoDefaults to "automation"
event_typestringnoDefaults to "payment_confirmed"
amount_centsintegernoPayment amount in cents (non-negative)
currencystringnoe.g. "USD"
paid_atstringnoISO 8601 timestamp
emailstringnoContact email hint
namestringnoContact name hint
external_refstringnoAdditional reference for replay lookup
metadataobjectnoArbitrary key/value pairs stored with the grant

* Exactly one of external_contact_id or ghl_contact_id is required. The grant creates the contact if it doesn’t exist yet, so non-GHL systems don’t need to sync contacts first.

Terminal window
curl -X POST https://app.<your-domain>/api/v2/grants \
-H "Authorization: Bearer ktly_<your-token>" \
-H "Content-Type: application/json" \
-d '{
"location_id": "loc_1",
"request_id": "grant_req_123",
"external_payment_id": "payment_123",
"ghl_contact_id": "ghl_contact_123",
"product_config_id": "pc_package_1",
"amount_cents": 9900,
"currency": "USD",
"paid_at": "2026-04-16T00:00:00.000Z"
}'
{
"ok": true,
"reason_code": "grant_applied",
"correlation_id": "a1b2c3d4-...",
"location_id": "loc_1",
"contact_id": "kotally-contact-uuid",
"entitlement_id": "kotally-entitlement-uuid",
"credits_granted": 10,
"balance_after": 10
}
  • credits_granted — derived from the product config, not the payment amount.
  • balance_after — the contact’s total available credits after the grant.
  • Re-sending the same external_payment_id returns duplicate_payment_event without granting again.
reason_codeMeaning
duplicate_payment_eventThe external_payment_id was already processed
BILLING_SUSPENDEDWorkspace billing is suspended
REQUEST_IN_PROGRESSSame request_id is still being processed — retry after a short delay

See the Overview for HTTP status codes and the full reason-code list.