Skip to main content

Troubleshooting: Apple Messages for Business onboarding and send failures

Apple Messages for Business (AMB) failures split into two moments: onboarding (the agent never reaches approved, or the webhook secret no longer verifies) and sending (a 422 naming a missing *Json metadata key, or a capability the agent does not hold). Both are deterministic, and neither is fixed by resending the same request. This page walks the failure surfaces the Apple Messages for Business channel page exposes, in triage order.

Symptom map

Agent stuck in pending — Apple-side clearance has not landed

A fresh registration returns 201 with status: "pending". Orbit cannot speed up Apple’s review: the agent flips to approved only when Apple clears the business on their side. The channel page’s polling pattern (re-fetch GET /api/v1/channels/amb/agents/{id} with exponential backoff) is the correct way to wait. Do not route live conversations to a pending agent. When the status never flips:
  1. Check Apple Business Register for an open action on the business entry. A missing document or a failed review keeps the agent pending no matter what Orbit does.
  2. Confirm the business_id you passed at create time is the approved identity, not a draft or sandbox one.
  3. Keep polling with backoff. No retry from your side moves the status.
  4. If the register shows the business as approved but the agent still reads pending, escalate: the MSP-side handoff is the remaining leg, and support can check it with your agent ID and business_id.

Suspended means repair or re-register

suspended is not a pause. Apple took the agent down after approval, for a policy or registration issue on their side. Treat any status regression as out-of-routing-set: resolve the cause in Apple Business Register, then repair the agent or re-register it before the next send. The onboarding guide’s polling loop throws on suspended for exactly this reason.

422 on a send: the missing *Json metadata key

An interactive send is a normal unified send with channel: "amb" and msgType: "interactive"; the Apple payload travels as a serialized JSON string in the matching metadata key: listPickerJson for list pickers, formJson for forms, timePickerJson for time pickers. A send missing the matching *Json metadata key is rejected with 422 naming the key. Fix the template and resend; nothing queues. Full-error sample, from a list-picker send that carried msgType: "interactive" but no listPickerJson:
Resolution:
  1. Read the key name off the rejection. It is exactly the key your send omitted.
  2. Add the serialized payload under that key. The value is a JSON string, not a nested object.
  3. Confirm the agent holds the matching capability (see the next section). A correct key on an agent without the capability fails the next gate.
  4. Resend. The reject is deterministic; the corrected body passes on the first retry.

Capability-gated rejects

Rich interactions and Apple Pay are agent-specific. An agent without interactive cannot carry a list picker; without form no form renders; without timePicker no timeslot sheet. Native Apple Pay needs both the applePay capability on the agent and a registered merchantIdentifier. Unsupported or malformed Apple payloads are rejected rather than rendered by another channel. Two shapes show up in practice:
  • Rich payload on an agent without the capability. The send is rejected or the payload is dropped. Read the agent record’s capabilities, enable the one the payload needs, or fall back to plain text for that conversation.
  • Native Apple Pay without the merchant identifier. The checkout resolver degrades by design: with applePayEnabled and merchantIdentifier both set it returns method: "native" and the Apple Pay sheet payload; otherwise it returns method: "hosted" with native null. If you expected a native sheet and received a hosted link, the merchant identifier is the gap. Register it with Apple and set it in the checkout config, or keep sending hosted.url into the thread. Both paths reconcile against the same paymentRequest, so your order logic does not fork. The commerce guide covers the decline-and-retry loop.

The HMAC secret at onboarding

The base64 HMAC secret_key you pass at agent creation authenticates the events Apple delivers to your AMB webhook. Orbit encrypts the key at rest and only exposes whether a secret is stored; it never returns the value.
  • Stored indicator set, events verifying. Nothing to do. This is the healthy state.
  • Secret lost on your side. You cannot read it back out of Orbit. Issue a new key in Apple Business Register and update the agent with the onboarding guide’s rotation steps. Until the stored secret matches Apple’s current one, inbound events fail verification.
  • Secret changed at Apple. Update the agent before the old key stops working. Rotating or deleting an agent changes webhook verification and routing for that Apple business.

Decision checklist

  1. Onboarding or send? pending/suspended and secret problems are onboarding; 422 and capability rejects are send-side.
  2. Onboarding: read the agent status. pending means wait on Apple and check the register; suspended means repair or re-register, with no sends in between.
  3. Send-side 422: read the key the rejection names, fix the template, resend once. Never retry the same body.
  4. Capability reject: compare the payload against the agent’s capabilities; for native pay, confirm the merchantIdentifier is registered and set.
  5. Webhook-side: check the stored-secret indicator; rotate when the secret changed at Apple.

What not to try

  • Do not send live traffic to a pending agent. Apple has not cleared it; the status will not move from your side.
  • Do not retry a 422 that names a *Json key. The reject is deterministic and nothing queues; the same body fails identically.
  • Do not move an Apple payload to another channel to dodge a capability reject. Apple payloads are not interchangeable with WhatsApp, RCS, or web-chat payloads; they are rejected rather than rendered elsewhere.
  • Do not expect Orbit to return your HMAC secret. Only the stored indicator is exposed; rotate instead.
  • Do not treat suspended as transient. It does not clear by itself; repair or re-register.

When to escalate

Open a support ticket when the register shows the business approved but the agent still reads pending after several days, when a corrected template still returns the same 422 naming the same key, or when native Apple Pay is configured with a registered merchant identifier but the resolver still returns hosted. Include:
  • The agent ID (data.id from the create response), not just the Apple business_id.
  • One meta.request_id from the rejection, for send-side failures.
  • The agent’s capabilities array and, for pay failures, the merchantIdentifier you configured.

See also