Browse documentation

Type to search the documentation. Press Esc to close.

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

FieldTypeDescription
namerequiredstringOr first_name and last_name, which are joined.
line1requiredstringAlso accepted as address1.
line2stringAlso accepted as address2.
cityrequiredstringCity.
staterequiredstringTwo-letter US state code.
ziprequiredstringAlso accepted as postal_code. Five digits, optionally with a +4.
countrystringDefaults to US.
messagestringThe finished text. Required only if the hook has no message template. When both are present, message wins.
handwritingstringOverrides the hook's handwriting.
design_idstringOverrides the hook's design.
arrive_onstringYYYY-MM-DD.
referencestringAlso read from id. Echoed into your card history.
Fire a hook with a flat payload
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"
  }'
201 Created
{
  "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 recipient object. 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_name filled {{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.

A hook message template
Congratulations, {{first_name}} — everyone at
{{sender_name}} is glad the {{deal_name}} deal came
through.
422 when the payload is missing a template field
{
  "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.

Request
curl https://scribblecards.com/api/v1/hooks/whk_YOURTOKEN
200 OK
{
  "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 GET never sends a card and never spends a credit. It exists because returning 405 here would fail some tools' setup wizards for no reason.
  • Note that a GET returns ready: true without checking the token, so it is not a way to test whether your token is correct. POST is.

#The token is the credential

Hook errors
StatusCodeCause
401invalid_hookThe URL is wrong, or the hook was deleted.
403hook_disabledThe hook was paused under Integrations.
422invalid_recipientA required address field is missing or malformed.
422template_incompleteThe template needs a field the payload has no value for.
422missing_messageNo message and the hook has no template.
402no_creditsThe 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.