Pickup pin validation request

📘

When is this event triggered?

This webhook is sent only when the delivery was dispatched with logistic_data.pickup_verification.pincode_owner = "abbiamo" in the Delivery request payload (the driver to seller pincode model — see Pickup pincode).

Abbiamo has already validated the PIN typed by the store operator against its own copy of the code. This call asks the carrier to unlock the driver in the carrier's app so the physical collection can proceed.

🚧

This webhook is synchronous

Abbiamo waits for the carrier's response on the same HTTP request — there is no callback. The HTTP status code and code field returned by the carrier directly decide whether the collection is released to the store operator.

  • Default timeout: 5 seconds. If your handler needs longer processing, respond 200 / driver_unlocked as soon as the unlock is committed in your database and finish the rest asynchronously on your side.
  • Retries: Abbiamo retries once on 5xx / timeout. There are no retries on 4xx responses.

Whenever the store operator submits the pickup PIN in the Abbiamo dashboard and Abbiamo confirms it locally, this event is fired to the carrier's webhook URL. The carrier must unlock the driver in its own app and respond synchronously.

The payload mirrors the same identifying blocks already sent on the original Delivery request (seller, carrier, delivery identifiers, logistic_data), so the carrier can locate the delivery in its own systems and reuse any context that arrived at dispatch time (e.g. a seller-specific token inside logistic_data.headers):

{
  "event_type": "PICKUP_PIN_VALIDATION_REQUEST",
  "event_at": "2026-05-12T14:34:17.890Z",
  "seller": {
    "seller_name": "Go Go Fruits",
    "seller_id": "eb064ede-08f3-470e-a37c-5b796a17cca8",
    "seller_document_number": "88399480000156",
    "seller_group_id": "b7d56bca-606e-405e-bf4d-9b0a3291b61d",
    "seller_contacts": [
      {
        "name": "Eduardo Silveira",
        "phone": "21999999999",
        "phone_country_code": "55",
        "email": "[email protected]"
      }
    ]
  },
  "carrier": {
    "name": "CARRIER_BRAND_NAME",
    "max_dispatched_time": "14:00:00-03",
    "expected_delivery_date": "2022-12-22T23:59:00.000-03:00",
    "total_expected_delivery_price": 1200,
    "method": {
      "external_id": "name/id",
      "id": "e84b2788-5b78-40dd-95cf-75807f70aaaa",
      "name": "CARRIER_BRAND_NAME_D0",
      "type": "D0"
    }
  },
  "invoice_number": "example_invoice_number_1",
  "invoice_access_key": "42081183123141000200550010000007010046403276",
  "delivery_id": "851dc274-e090-4881-8f3c-5b660cecf059",
  "order_number": "example_carrier_payload_1",
  "logistic_data": {
    "headers": {
      "Authorization": "Bearer xxx"
    },
    "pickup_verification": {
      "pincode": true,
      "pincode_owner": "abbiamo",
      "pincode_value": "8745"
    }
  }
}
❗️

This is a release call, not a re-validation

Abbiamo is the source of truth for the PIN in the driver to seller pincode model and has already validated it locally before firing this webhook. The carrier must not re-validate the pincode_value echoed inside logistic_data.pickup_verification — the only purpose of this endpoint is to unlock the driver in the carrier's app.

The pincode_value is echoed here only because the whole logistic_data block is re-sent for convenience (so the carrier can reuse any context it relied on at dispatch — most often a seller-specific token inside logistic_data.headers). If the carrier does not need that context, it can safely ignore everything other than delivery_id.

Expected responses

The carrier must reply on the same HTTP response. Abbiamo uses the response to decide whether to transition the delivery to COLLECTED and release the collection on the store side.

HTTPcodeMeaning
200driver_unlockedDriver was unlocked in the carrier's app. Abbiamo transitions the delivery to COLLECTED and returns success to the store operator.
200already_unlockedDriver was already unlocked (idempotent retry of the same delivery_id). Same effect as driver_unlocked.
404DELIVERY_NOT_FOUNDThe carrier does not recognize this delivery_id. Abbiamo surfaces the error to the operator. No retry.
409INVALID_DRIVER_STATUSThe driver is no longer in a valid state to collect (already gave up, already left the pickup point, etc.). Abbiamo blocks the collection. No retry.
5xx / timeoutAbbiamo retries once immediately. If it still fails, the operator sees a "carrier unavailable" error in the dashboard and the delivery stays put.

Example response for 200 / driver_unlocked:

{
  "code": "driver_unlocked",
  "delivery_id": "851dc274-e090-4881-8f3c-5b660cecf059",
  "unlocked_at": "2026-05-12T14:34:18.014Z",
  "driver": {
    "name": "Carlos Silva",
    "document_number": "12345678900"
  }
}
👍

Idempotency is required

The carrier endpoint must accept a second call with the same delivery_id without side effects and reply 200 / already_unlocked. Abbiamo treats driver_unlocked and already_unlocked equivalently as success, which keeps the retry behavior safe.

Where to register the URL

The endpoint that listens for this event lives at the same URL the carrier registers for DELIVERY_REQUEST and CANCELLATION_REQUEST events — or at a separate URL if you prefer. See Receive events for the registration step. Carriers that do not yet support the driver to seller pincode model can skip registering this URL; in that case, Abbiamo simply never dispatches deliveries with pincode_owner = "abbiamo" to your integration.