Skip to documentation
Anywe

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.

The boundary
  1. Receive

    raw body

  2. Verify

    exact bytes

  3. Dedupe

    X-Delivery-Id

  4. Acknowledge

    2xx, fast

  5. Work

    off request

  6. 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 --relay for 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:

Go
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.

  1. Receive and verify

    Read a bounded raw request body, verify X-Platform-Signature over those exact bytes, then inspect the authenticated X-Delivery-Id. Store that ID as the incoming deduplication key before parsing the envelope or handing it to your service.

  2. 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.

  3. Reply asynchronously

    Build a reply whose in_reply_to_delivery_id is the received delivery ID, sign the final bytes, and POST /hooks/v1/reply with Idempotency-Key set 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