Scribble inbound hooks: send a card from any tool
For developers
An inbound hook is one URL that sends one card every time something POSTs JSON to it. The token in the URL is the credential, so no API key is needed. The hook carries its own design, handwriting and message template, which is what lets a Zapier payload be as small as a name and an address.
On this page
#Why this exists instead of twelve connectors
Every tool a customer already uses can POST JSON to a URL: Zapier, Make, n8n, a Salesforce Flow, a Shopify Flow action, a GitHub Action, four lines in their own backend. One URL that sends one card makes all of them work today, without an OAuth app per vendor that then has to be maintained.
#POST/api/v1/hooks/{token}
Send one handwritten card. The token in the URL is the credential.
No API key. The token in the URL is the credential.
Body parameters
| Field | Type | Description |
|---|---|---|
namerequired | string | Or first_name and last_name, which are joined. |
line1required | string | Also accepted as address1. |
line2 | string | Also accepted as address2. |
cityrequired | string | City. |
staterequired | string | Two-letter US state code. |
ziprequired | string | Also accepted as postal_code. Five digits, optionally with a +4. |
country | string | Defaults to US. |
message | string | The finished text. Required only if the hook has no message template. When both are present, message wins. |
handwriting | string | Overrides the hook's handwriting. |
design_id | string | Overrides the hook's design. |
arrive_on | string | YYYY-MM-DD. |
reference | string | Also read from id. Echoed into your card history. |
curl -X POST https://scribblecards.com/api/v1/hooks/whk_YOURTOKEN \
-H "Content-Type: application/json" \
-d '{
"first_name": "Dana",
"last_name": "Okafor",
"line1": "88 Colin P Kelly Jr St",
"city": "San Francisco",
"state": "CA",
"zip": "94107",
"deal_name": "Q3 renewal",
"id": "deal_9931"
}'{
"id": "SC-2CR9793",
"object": "card",
"status": "scheduled",
"held_reason": null,
"arrives_between": {
"earliest": "2026-08-12",
"latest": "2026-08-14"
},
"url": "https://scribblecards.com/app/orders/SC-2CR9793"
}- Recipient fields may be at the top level or nested inside a
recipientobject. Both are read, so a flat Zapier field map works without a wrapper. - Any other field in the payload is available to the hook's message template. In the example above,
deal_namefilled{{deal_name}}. - The card written by that request read: Congratulations, Dana — everyone at Northwind is glad the Q3 renewal deal came through.
#Message templates
A hook's message template is what makes it usable from a tool with no text box. Fields come from the payload, plus {{first_name}} and {{full_name}} derived from the recipient, plus {{sender_name}} from the hook's Signed by setting.
Congratulations, {{first_name}} — everyone at
{{sender_name}} is glad the {{deal_name}} deal came
through.{
"error": {
"code": "template_incomplete",
"message": "This hook's message template needs deal_name, and the payload has no value for it. Send those fields, or send a finished `message` instead.",
"docs": "https://scribblecards.com/app/integrations"
}
}#GET/api/v1/hooks/{token}
Verification ping. Some tools fetch an endpoint before they will save it.
No API key. The token in the URL is the credential.
curl https://scribblecards.com/api/v1/hooks/whk_YOURTOKEN{
"object": "inbound_hook",
"ready": true,
"message": "This hook is live. POST a JSON body with a recipient to send a card.",
"example": {
"name": "Priya Raman",
"line1": "1 Fifth Avenue",
"city": "New York",
"state": "NY",
"zip": "10003",
"message": "Congratulations from all of us."
}
}- A
GETnever sends a card and never spends a credit. It exists because returning405here would fail some tools' setup wizards for no reason. - Note that a
GETreturnsready: truewithout checking the token, so it is not a way to test whether your token is correct. POST is.
#The token is the credential
| Status | Code | Cause |
|---|---|---|
| 401 | invalid_hook | The URL is wrong, or the hook was deleted. |
| 403 | hook_disabled | The hook was paused under Integrations. |
| 422 | invalid_recipient | A required address field is missing or malformed. |
| 422 | template_incomplete | The template needs a field the payload has no value for. |
| 422 | missing_message | No message and the hook has no template. |
| 402 | no_credits | The balance is empty. Nothing was created. |
#Named connectors
There is no HubSpot app, Salesforce package, Shopify app or Pipedrive integration. You can request one from Integrations → Named connectors, and the request is recorded against your company, which is how the build order gets set. In the meantime every one of those tools can fire a hook today.
#Common questions
- How many hooks can I have?
- As many as you want. One per trigger is the right shape, because each carries its own design, handwriting and message template, and each has its own fire count and log.
- Is a hook rate limited?
- Not by the API key limiter, because there is no key. One POST is still one card and one credit, so put the guard on your trigger.
- Can a hook send to more than one person?
- No. One POST, one card.
- How do I know a hook fired?
- The Integrations screen shows a fire count, a last-fired timestamp and a log of every call with its status and reason.
Last checked against the product on . Something wrong or missing? Tell us.