Skip to content

Run webhooks, inbound routes, and background jobs

Receive events in an app and hand slow work to a job. Begin with a working function and an installation with the permissions needed by that work. Use idempotent handlers because events and jobs can retry.

init already created lifecycle hooks under src/app/lifecycle/ that call on-install, on-update, on-uninstall, and on-rotate. Add the trigger you actually need:

Terminal window
caraer apps add function catch-created
caraer apps add webhook --topic record.candidate.created --function catch-created
caraer apps add schedule heartbeat --function catch-created --cron "0 0 */12 * * *"
caraer apps add inbound provider-push --function catch-created --auth SHARED_SECRET

Record webhooks are always object-scoped: record.{object}.{created|updated|deleted|all}. There is no company-wide record.created topic.

Trigger Use when
Webhook (record.candidate.created, …) A record event on that object should run your code
Inbound An external system POSTs to a public URL
Schedule Cron (Spring 5–6 field expression)
Lifecycle Install, settings save, uninstall, or token rotate
App bar A button on a record, a trait tab, or a sidebar tool. See App bars in Caraer apps

There is no copyable inbound URL in the Caraer app today. After deploy, assemble it from the API host, the app UUID (caraer.json / caraer apps select), the route name in src/app/inbound/<name>.json, and the installing company UUID (caraer company list):

POST {caraerApiBase}/v2/public/apps/{appUuid}/inbound/{routeName}?companyUuid={companyUuid}
Content-Type: application/json
X-Caraer-Inbound-Secret: <shared-secret>

companyUuid can also be sent as X-Caraer-Company-Uuid instead of a query param. For SHARED_SECRET routes, send the secret in X-Caraer-Inbound-Secret. validate warns if sharedSecret is missing.

Pass data in the JSON body. The function receives:

{
"action": "app.inbound",
"inboundRoute": "provider-push",
"body": { "hello": "caraer" }
}

Query params other than companyUuid are not forwarded. Auth headers are used only to verify the caller.

Locally, caraer apps local dev prints POST http://127.0.0.1:8787/inbound/<routeName> and accepts the same JSON body.

enqueue: true (the default) returns 202 and runs the function as a job. Long work should enqueue and return quickly.

Use POST {caraerApiBase}/v2/apps/{appUuid}/installation/jobs with a functionName, payload, and optional delaySeconds. Read the current installation runtime API for limits and job status operations. Use state for cursors or deduplication markers; keep credentials in the secrets vault.

Test a local sample first, then send a real event to a sandbox deployment. Confirm the queued job and its result. An accepted inbound request or READY runtime alone does not prove the job or external provider completed.

The published CLI accepts webhookFormat: MINIMAL and a comma-separated fields selection on record webhooks. This reduces the main record’s properties; it does not project related records. Use internal field names and verify the selected app’s backend supports the requested format:

Terminal window
caraer webhooks formats

In a function’s exported manifest, the webhook can include:

export const manifest = {
webhooks: [{
topic: 'record.<setting:target_object>.created',
webhookFormat: 'MINIMAL',
fields: 'firstname,email',
}],
};

MINIMAL excludes user/context metadata and recognised webpage fields. Non-relation events omit event metadata. Relation creation, update, and deletion include a compact event so your receiver can identify the changed link, even after deletion:

{
"record": {"uuid": "contact-a", "objectName": "contact", "properties": {"firstname": "Jane"}},
"relations": {},
"event": {
"type": "relation_created",
"relationName": "works_at",
"fromRecord": {"uuid": "contact-a", "objectName": "contact"},
"toRecord": {"uuid": "company-b", "objectName": "company"}
}
}

Here the changed link is works_at from contact-a to company-b. Updates and deletions use relation_updated and relation_deleted. record is the watched endpoint; event.fromRecord and event.toRecord keep the original direction even when watching the target. Same-object and self-links retain both endpoint identities. Endpoints contain only uuid and objectName, never properties; legacy events with missing endpoint or relation data omit those fields. fields affects only the main record’s properties, not endpoint identity. relations holds additionally requested records, not the changed link. Use USER_FRIENDLY when your handler needs the normal event envelope. Set fields: '' to clear a saved selection; omitting it means all available main record properties. The CLI preserves these settings on pull and push.

Resume an automatically deactivated webhook

Section titled “Resume an automatically deactivated webhook”

Restore the destination before resuming deliveries. Company record-event webhooks, including record.<object>.date_due.<property> subscriptions, automatically stop after three combined HTTP 400/404 responses, counting retry attempts. A 2xx response resets the counter; other errors leave it unchanged. HTTP 410 stops the subscription immediately. These rules apply to HTTP and serverless deliveries. Only the affected company’s subscription stops; the webhook definition and other companies remain. Lifecycle and app-bar hooks do not automatically deactivate, and HTTP 410 no longer deletes webhook definitions on any delivery path.

With CLI 0.1.12 or later, inspect the selected company’s state:

Terminal window
caraer company select <company-uuid>
caraer webhooks list --app <app-uuid>
caraer webhooks show <webhook-uuid> --app <app-uuid>

List/detail responses expose read-only deactivated, failureCount, lastFailureStatus, lastFailureAt, deactivatedAt, and deactivationReason. Timestamps are Unix milliseconds. Older subscriptions default to active with a zero counter. The app’s Webhooks list and editor show Automatically deactivated, the HTTP status and time, and a Reactivate action. A failed reactivation leaves the warning visible.

After fixing and testing the destination, explicitly resume future deliveries:

Terminal window
caraer webhooks reactivate <webhook-uuid> --app <app-uuid>
caraer webhooks show <webhook-uuid> --app <app-uuid>

The caller needs the existing app-resource edit permissions and access to the selected company’s subscription; knowing its UUID is insufficient. Expect deactivated: false and failureCount: 0. Last incident metadata remains. Send a new sandbox event and verify its delivery: reactivation does not replay old queued events. Requests already in flight may finish, but their results cannot change the reactivated state.

Tests remain available while deactivated and neither advance nor reset the counter. Configuration edits, installation rematerialization, deployments, and manifest enabled values preserve automatic deactivation. Use the explicit reactivation action rather than pushing configuration to resume deliveries.

For these company subscriptions, 400/404/410 failures no longer retain full payloads in the dead-letter store (the store for failed deliveries). A pending 404 retry can retain its payload until success, retry exhaustion, or deactivation. Deactivation discards pending retries and date-scheduled work for that company. Other failures, including 413 and 5xx, keep their existing retry/dead-letter policy.

The API action is POST /api/v2/apps/{appUuid}/webhooks/{webhookUuid}/reactivate. See the API reference and authentication guide for Bearer authentication and company selection.

The published Python client adds ApplicationsApi.reactivate_app_webhook(app_uuid, webhook_uuid) and the runtime status fields. ShowResponseSubscribeWebhookDTO.data now contains a SubscribeWebhookDTO model instead of a dictionary. Replace dictionary access such as response.data["deactivated"] with model attributes:

webhook = response.data
print(webhook.deactivated, webhook.failure_count)

For a successful reactivation response, expect False 0. Use webhook.last_failure_status, webhook.last_failure_at, webhook.deactivated_at, and webhook.deactivation_reason for incident details. to_dict() excludes these read-only runtime fields, including deactivated and failure_count; inspect the attributes directly. Configuration serialization cannot reactivate a webhook.