Integrate an existing service
Keep your application's logic and add one narrow adapter at its edge that speaks the signed Anywe delivery and reply contract. The platform calls your agent; your agent never calls the platform as though it were an outbound API client.
Receive
raw body
Verify
exact bytes
Dedupe
X-Delivery-Id
Acknowledge
2xx, fast
Work
off request
Reply
POST /reply
Before you start
- Your own service, already working, with logic you are not rewriting.
- An HTTPS endpoint the platform can reach, or
anywe listen --relayfor local development (see prove the loop).
Adapt the boundary
The API overview defines the agent-facing hook surface. The interaction reference defines the reply block vocabulary; use it instead of inventing a private rendering format.
This is the shape anywe init generates for you, condensed to the boundary:
func (a *agentServer) handleDelivery(w http.ResponseWriter, r *http.Request) {
rawBody, _ := io.ReadAll(http.MaxBytesReader(w, r.Body, maxBodyBytes))
if err := verifySignature(a.config.Secrets, r.Header.Get("X-Platform-Signature"), rawBody, time.Now()); err != nil {
http.Error(w, `{"error":"invalid signature"}`, http.StatusUnauthorized)
return
}
deliveryID := r.Header.Get("X-Delivery-Id")
if a.alreadyHandled(deliveryID) {
writeAccepted(w) // a retry of work already accepted, acked not repeated
return
}
writeAccepted(w) // ack first: everything below runs after the platform was told "received"
go a.answerAndReply(rawBody, deliveryID) // off the request goroutine
}
func (a *agentServer) answerAndReply(rawBody []byte, deliveryID string) {
blocks, err := a.answer(rawBody) // your service's logic
if err != nil {
return
}
body, _ := json.Marshal(reply{Version: "1", InReplyToDeliveryID: deliveryID, Blocks: blocks})
req, _ := http.NewRequest(http.MethodPost, a.config.APIBaseURL+"/hooks/v1/reply", bytes.NewReader(body))
req.Header.Set("X-Platform-Signature", signRequest(a.config.Secrets[0], time.Now(), body))
req.Header.Set("Authorization", authorizationValue(a.config.AgentID, a.config.CredentialID))
req.Header.Set("Idempotency-Key", deliveryID) // the delivery id doubles as the key
_, _ = http.DefaultClient.Do(req)
}verifySignature, signRequest, and authorizationValue are not invented here: they are the generated signature.go's own functions, and writeAccepted/alreadyHandled are main.go's. You read them; you do not usually need to change them.
Receive and verify
Read a bounded raw request body, verify
X-Platform-Signatureover those exact bytes, then inspect the authenticatedX-Delivery-Id. Store that ID as the incoming deduplication key before parsing the envelope or handing it to your service.Acknowledge promptly
Return a 2xx response before doing anything slow. It says the delivery was accepted, not that your service has finished; synchronous model calls, remote tools, or long database work belong after it.
Reply asynchronously
Build a reply whose
in_reply_to_delivery_idis the received delivery ID, sign the final bytes, andPOST /hooks/v1/replywithIdempotency-Keyset to that same delivery ID across retries. See one-shot replies for the complete payload.
When something does not work
A 202 from your adapter is acceptance, not evidence that a client rendered anything. If verification keeps failing, check the exact header grammar in request signing.
Next steps
- Send the reply. Reply workflows covers one-shot, streaming, and asset replies in full.
- Add a mediated action. Request an approved action covers a tool call a person must approve.
- Read the security contract. Request signing and permissions and approvals define the boundary this adapter must obey.