Masheev Developers

Open Markdown · Agent index

Outbound calls and server workflows

Availability: off. outbound_calling, transactional_sms and outgoing_webhooks remain disabled. These schemas describe preparation and future integration; they do not authorize production calls, SMS or webhook delivery. See availability and authentication. Organization API keys belong on your server.

Prepare a consented campaign

Owners and organization administrators can create campaigns and consent sources, record consent, manage suppression and request higher limits. Members can read. Platform review and verified seller identity are separate from organization setup. Approved consent wording is immutable: create a new source to change it. An immutable rejected source can be resubmitted with outbound.consentSources.submit and a stable idempotencyKey. Replaying that key cannot reopen a later review decision.

Use outbound.status for current eligibility. Create a campaign, configure at most three variants, add consented leads with outbound.requests.add, then preview with outbound.preview (up to 1,000 phones per read-only batch) or outbound.check. Previewing a draft treats its campaign as running, but preserves all other policy checks. Preview does not reserve capacity or persist inline consent. Actual calling requires enablement and rechecks current consent, withdrawal, ownership, windows and limits immediately before dialing and answering.

Launch requires explicit confirmation of schedule and retry settings. Pausing stops new dials and cancels ringing/unsent attempts while preserving queued leads; active conversations finish. Resume waits until uncertain stop effects resolve. Completing or archiving cancels queued work; archiving retires snapshot agents for later provider cleanup. Canceling an explicitly requested callback leaves a human follow-up in its conversation. Request cancellation targets its exact current call.

Use stable per-row idempotency keys for enqueue retries. Public list imports also deduplicate by campaign and phone. Trusted workflow calls use a separate logical request per run/step, so two bookings for one person keep independent results. Customer context and metadata never grant consent or callback authority.

Reconcile results

Read outbound.requests.list with updatedSince, follow every nextCursor, and deduplicate by request ID. This is the reconciliation path after missed events. Use outbound.calls.list and outbound.calls.get for public live-call state; provider credentials, transport payloads and private consent/callback proofs are not public.

Events are call.completed, outbound.request.completed, outbound.callback.scheduled and outbound.campaign.paused. They carry stable eventId/occurredAt values and bounded, redacted customer metadata. A completed request may have result: null; cancellation is not success. Call status can arrive before extracted results; request completion waits for authoritative extraction or the documented recovery backfill. Never infer a confirmed booking from a missing boolean. Statistics exclude test calls; cost is billed USD (including recorded billing shortfall), not provider conversation units. Conversion intervals are Wilson 95%; a winner requires at least 100 human answers per arm and non-overlapping intervals.

Send authenticated server events

POST /v1/events (also exposed as the events.ingest procedure) requires an organization API key with write permission and matching orgId. Send from your backend. Never invoke workflow webhook triggers from a browser or expose keys there.

{
  "orgId": "your-organization",
  "type": "booking.created",
  "occurredAt": "2030-01-10T09:00:00Z",
  "idempotencyKey": "booking-created-123-v1",
  "subject": { "phone": "+442079460123", "externalId": "booking-123" },
  "data": { "startAt": "2030-01-10T15:00:00Z" }
}

Supported types include booking.created, booking.updated, booking.cancelled and custom.*. The subject phone must be valid E.164. Masheev resolves the contact; do not supply authoritative contact, lineage or permission fields in data. Inside a run, values are trigger.data.subject.externalId, trigger.data.subject.phone, trigger.data.contactId and trigger.data.startAt. accepted: true means durable admission; queued: false means publication awaits recovery. Reuse the same key and identical payload after an uncertain response.

A durable cancellation revokes the exact organization's phone/booking reference. A stale update cannot revive it. Reusing a canceled external ID as a new booking requires an explicitly supported generation model; do not rely on such reuse today.

Durable waits and action outputs

Time waits accept { "until": "{{trigger.data.startAt}} - 3h" }. Event waits accept:

{
  "for": {
    "events": ["outbound.request.completed"],
    "match": { "key": "requestId", "value": "{{steps.call.requestId}}" },
    "timeoutMs": 7200000
  }
}

SQL-backed waits resume from the stored workflow definition. A timeout produces steps.<waitId>.timedOut; an event produces steps.<waitId>.event. The booking result fields are flat: steps.call_result.event.data.metadata.result.confirmed and .cancel_requested, not result.collected.

  • builtin:place_call: {campaignId, context?}. Uses the trusted booking subject, a service campaign, and booking-scoped transaction consent. Returns requestId.
  • builtin:send_sms: {inboxId, template:"booking_confirmation"}. Requires approved sender registration, transaction consent and no applicable opt-out. Uses a fixed service message with STOP footer. Returns messageId and conversationId.
  • builtin:http_request: {connectionId, body}. Uses an owned active server-side signing connection. No raw URL or signing secret appears in the workflow step.
  • TablePort: only sdk:tableport/get-booking, modify-booking and cancel-booking. Booking identity comes from the trusted run; arbitrary foreign booking IDs fail.

Correlate SMS reply waits by the returned conversationId. Authenticated inbound SMS events include channel:"sms", classification:"confirm"|"cancel"|"other", and tenant/contact/inbox/conversation IDs. Several active booking conversations for one recipient make a reply ambiguous; it is classified other, with correlationAmbiguous:true. Do not guess a booking from free-text replies.

Booking template and external dependencies

The editable Booking confirmation (SMS → call) template waits until three hours before the booking, reads latest booking state, sends SMS, waits 30 minutes, and calls when there is no reply. Configure an approved SMS inbox, an always-on service campaign with boolean confirmed and cancel_requested fields plus string reschedule_note, and separate signed HTTP destinations for confirmation and staff follow-up. The template rechecks latest booking/cancellation state before contacting the person.

TablePort is a separate company and deployment. This Masheev implementation does not install a TablePort publisher, grant access to TablePort data, modify TablePort code, or establish contractual coverage. TablePort must independently implement its authorized server event publisher. Its current Masheev adapter has no confirmed-status mutation contract; the template uses a configured signed HTTP confirmation action. A receiving service must implement that contract before the branch can complete. Do not add an invented status:"confirmed" parameter to modify-booking.

Signed destinations must be dedicated public HTTPS origins. Each request resolves DNS and pins a checked public IP while validating TLS for the original hostname; Cloudflare-proxied destinations are unsupported by the Workers socket transport. There are no redirects or unpinned fallback, a ten-second deadline, and a 64 KiB response limit. Verify X-Masheev-Signature (sha256= HMAC-SHA256 over exact UTF-8 body bytes) and deduplicate the stable Idempotency-Key on the receiver. Mutation outcomes that cannot be proven are retained for reconciliation, not blindly repeated.

Isolated staging rehearsals before public enablement

Public outbound_calling remains off. After explicit owner approval of the test number, transfer destinations and costs, an operator may configure OUTBOUND_REHEARSAL_GRANT in an isolated staging environment. This is an operator configuration, never a public request parameter. No grant is supplied by this repository, and configuring one does not establish the separate launch approvals.

The strict JSON grant contains id, orgId, campaignId, variantId, phoneE164, UTC issuedAt/expiresAt, and transferTargets entries containing ruleId and to. Its lifetime must be at most two hours. Only ENVIRONMENT=staging accepts it; production, development, missing, expired and mismatched grants fail closed. Preparation requires a campaign with exactly one non-stopped variant, matching the grant. OTP verification is limited to the exact granted number and retains the ordinary verification rate limits.

Only the exact campaign/variant's verified source=test requests may use the exception. Normal API, list and workflow requests remain unavailable. The org still needs beta enrollment, approval, paid access, current outbound attestation and seller identity; kill switches, suspension, suppression, country, caller ownership, billing and capacity controls remain authoritative. Verified test calls retain their documented consent/window exception. Claim, answer and transfer read current authority; transfer rule and destination must both match. Expired grants always fail closed. Removing the grant affects operations handled by Workers running the updated configuration; it does not mutate an existing isolate's environment. Fresh primary workspace suspension is the existing immediate operator control. End an already connected call through call controls.

The live harness accepts --staging-rehearsal only with the repository-configured https://api.staging.masheev.com origin. That flag skips only its redundant global status check; the server authorizes every operation. The normal harness keeps that check. Owner-number matching and both cost acknowledgements are still required. Grant contents are excluded from public status, logs and receipts.

Staging's scheduled triggers remain disabled in Wrangler until isolated database and provider readiness is established. An authorized operator must arrange that readiness and normal scheduler/recovery operation before rehearsing. This code change enables neither schedules nor provider resources, sends no calls, and provides no live proof by itself.

Both transfer rehearsal scenarios require --rule-id and validate its destination against the owner-approved transfer number. For the secondary path, request the approved human handoff and have the agent use end_call before the watchdog fires; only observed redirect proof passes. Instructions alone are not evidence. Run scenarios separately as person-level redial gates permit, issuing separate short-lived operator grants when necessary rather than relaxing those gates.