> ## Documentation Index
> Fetch the complete documentation index at: https://docs.drop-hub.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create one shipment from a merchant reference and two location pins

> DropHub derives address and city context, route, coverage, pricing, carrier eligibility, service and dispatch decisions, SAR/payment defaults, lifecycle defaults, and the customer tracking URL. Idempotency-Key is optional because the merchant reference is the default key.



## OpenAPI

````yaml /openapi.yaml post /v2/external/shipments
openapi: 3.1.0
info:
  title: DropHub External API
  version: v2
  description: The public machine-to-machine integration surface of DropHub.
servers:
  - url: https://api-test.drop-hub.com
    description: Sandbox. Isolated data and credentials.
  - url: https://api.drop-hub.com
    description: Production. Production credentials only.
security: []
tags:
  - name: Authentication
    description: OAuth 2.0 client-credentials token issuance
  - name: External Shipments
    description: Create, read, and cancel your shipments
  - name: External Tracking
    description: Partner and customer-safe shipment progress
  - name: External Webhooks
    description: Your single signed shipment webhook
paths:
  /v2/external/shipments:
    post:
      tags:
        - External Shipments
      summary: Create one shipment from a merchant reference and two location pins
      description: >-
        DropHub derives address and city context, route, coverage, pricing,
        carrier eligibility, service and dispatch decisions, SAR/payment
        defaults, lifecycle defaults, and the customer tracking URL.
        Idempotency-Key is optional because the merchant reference is the
        default key.
      operationId: createExternalShipment
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalShipmentRequest'
            examples:
              minimal:
                value:
                  reference: ORDER-1042
                  pickup:
                    latitude: 24.7136
                    longitude: 46.6753
                  destination:
                    latitude: 24.774265
                    longitude: 46.738586
                  recipient:
                    name: Noura
                    mobile: '0551234567'
              savedPickupCod:
                value:
                  reference: ORDER-1043
                  pickup:
                    savedLocationCode: MAIN
                  destination:
                    latitude: 24.774265
                    longitude: 46.738586
                  recipient:
                    name: Noura
                    mobile: '+966551234567'
                  parcel:
                    description: Small box
                    pieces: 1
                    weightKg: 2.4
                  codAmount: 125
      responses:
        '200':
          $ref: '#/components/responses/ExternalShipmentResource'
        '201':
          $ref: '#/components/responses/ExternalShipmentCreated'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/AuthenticationFailed'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '409':
          $ref: '#/components/responses/StateConflict'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/ProviderUnavailable'
      security:
        - oauthClientCredentials:
            - shipments:write
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >-
        Optional. Retry safety is handled for you: when this header is absent
        DropHub derives the key from the reference you already send — the order
        number on a shipment create, the shipment id on a cancel — scoped to
        your merchant account. Two calls naming the same order are treated as
        one submission and the second returns the original result. Send your own
        key only if you want to control the replay window yourself; an explicit
        key always wins.
      schema:
        type: string
        minLength: 16
        maxLength: 128
        example: merchant-order-20260822-0001
  schemas:
    ExternalShipmentRequest:
      type: object
      additionalProperties: false
      required:
        - reference
        - pickup
        - destination
        - recipient
      properties:
        reference:
          type: string
          minLength: 1
          maxLength: 128
          description: Merchant order/reference number and default idempotency key.
        pickup:
          $ref: '#/components/schemas/ExternalPickup'
        destination:
          $ref: '#/components/schemas/ExternalCoordinate'
        recipient:
          $ref: '#/components/schemas/ExternalRecipient'
        parcel:
          $ref: '#/components/schemas/ExternalParcel'
        codAmount:
          type: number
          format: decimal
          exclusiveMinimum: 0
          multipleOf: 0.01
          description: Omit for prepaid shipments; currency is SAR.
        pickupWindow:
          $ref: '#/components/schemas/ExternalPickupWindow'
    ExternalPickup:
      description: Use either a saved pickup code or a coordinate pin.
      oneOf:
        - type: object
          additionalProperties: false
          required:
            - savedLocationCode
          properties:
            savedLocationCode:
              type: string
              pattern: ^[A-Z0-9][A-Z0-9_-]{1,63}$
        - $ref: '#/components/schemas/ExternalCoordinate'
    ExternalCoordinate:
      type: object
      additionalProperties: false
      required:
        - latitude
        - longitude
      properties:
        latitude:
          $ref: '#/components/schemas/Latitude'
        longitude:
          $ref: '#/components/schemas/Longitude'
    ExternalRecipient:
      type: object
      additionalProperties: false
      required:
        - name
        - mobile
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
        mobile:
          type: string
          pattern: ^(?:05|5|\\+9665)[0-9]{8}$
          description: Saudi mobile; DropHub stores canonical +9665XXXXXXXX.
    ExternalParcel:
      type: object
      additionalProperties: false
      properties:
        description:
          type: string
          minLength: 1
          maxLength: 160
          default: Parcel
        pieces:
          type: integer
          minimum: 1
          maximum: 100
          default: 1
        weightKg:
          type: number
          exclusiveMinimum: 0
          default: 1
    ExternalPickupWindow:
      type: object
      additionalProperties: false
      required:
        - start
        - end
      properties:
        start:
          $ref: '#/components/schemas/InstantUtc'
        end:
          $ref: '#/components/schemas/InstantUtc'
    ExternalShipment:
      type: object
      additionalProperties: false
      required:
        - id
        - reference
        - status
        - trackingUrl
        - createdAt
        - version
      properties:
        id:
          $ref: '#/components/schemas/Uuid'
        reference:
          type: string
        status:
          $ref: '#/components/schemas/ExternalShipmentStatus'
        trackingUrl:
          type: string
          format: uri-reference
        codAmount:
          type:
            - number
            - 'null'
          format: decimal
          minimum: 0
        createdAt:
          $ref: '#/components/schemas/InstantUtc'
        version:
          type: integer
          format: int64
          minimum: 0
    Problem:
      type: object
      description: RFC 9457 Problem Details with stable DropHub extensions
      additionalProperties: true
      required:
        - type
        - title
        - status
        - code
        - timestamp
        - correlationId
        - requestId
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
          maxLength: 128
        status:
          type: integer
          format: int32
          minimum: 400
          maximum: 599
        detail:
          type: string
          maxLength: 512
        instance:
          type: string
          format: uri-reference
        code:
          type: string
          pattern: ^[A-Z][A-Z0-9_]{1,63}$
        timestamp:
          type: string
          format: date-time
        correlationId:
          type: string
          format: uuid
        requestId:
          type: string
          format: uuid
        traceId:
          type: string
          pattern: ^[0-9a-f]{32}$
        violations:
          type: array
          maxItems: 20
          items:
            $ref: '#/components/schemas/Violation'
      example:
        type: https://api.drop-hub.com/problems/access-denied
        title: Access denied
        status: 403
        detail: Access to this resource is denied.
        instance: /v2/external/shipments/018f2d8a-1f00-7000-8000-000000000206
        code: ACCESS_DENIED
        timestamp: '2026-08-22T18:30:00Z'
        correlationId: 018f2d8a-1f00-7000-8000-000000000207
        requestId: 018f2d8a-1f00-7000-8000-000000000208
    Latitude:
      type: number
      minimum: -90
      maximum: 90
      multipleOf: 0.000001
      x-java-type: java.math.BigDecimal
      x-postgresql-type: numeric(9,6)
      x-unit: decimal-degrees
    Longitude:
      type: number
      minimum: -180
      maximum: 180
      multipleOf: 0.000001
      x-java-type: java.math.BigDecimal
      x-postgresql-type: numeric(10,6)
      x-unit: decimal-degrees
    InstantUtc:
      type: string
      format: date-time
      x-java-type: java.time.Instant
      x-postgresql-type: timestamptz(6)
      x-time-semantics: UTC-instant
    Uuid:
      type: string
      format: uuid
    ExternalShipmentStatus:
      type: string
      enum:
        - CREATED
        - ASSIGNED
        - PICKED_UP
        - OUT_FOR_DELIVERY
        - DELIVERED
        - FAILED
        - CANCELLED
    Violation:
      type: object
      additionalProperties: false
      required:
        - field
        - code
        - message
      properties:
        field:
          type: string
          maxLength: 128
        code:
          type: string
          maxLength: 64
        message:
          type: string
          maxLength: 256
  responses:
    ExternalShipmentResource:
      description: Minimal partner-safe shipment
      headers:
        ETag:
          $ref: '#/components/headers/EntityTag'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalShipment'
    ExternalShipmentCreated:
      description: Shipment created; a retry of the same request returns 200 instead.
      headers:
        ETag:
          $ref: '#/components/headers/EntityTag'
        Location:
          schema:
            type: string
            format: uri-reference
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalShipment'
    BadRequest:
      description: >-
        The request syntax, path parameter, query parameter, or JSON document is
        malformed.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    AuthenticationFailed:
      description: >-
        Authentication failed: the bearer token is missing, malformed, or
        expired.
      headers:
        WWW-Authenticate:
          $ref: '#/components/headers/WwwAuthenticate'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.drop-hub.com/problems/authentication-required
            title: Authentication required
            status: 401
            detail: Authentication is required for this resource.
            instance: /v2/external/shipments/018f2d8a-1f00-7000-8000-000000000206
            code: AUTHENTICATION_REQUIRED
            timestamp: '2026-08-22T18:30:00Z'
            correlationId: 018f2d8a-1f00-7000-8000-000000000207
            requestId: 018f2d8a-1f00-7000-8000-000000000208
    AccessDenied:
      description: >-
        The token is valid but the credential lacks the required scope, or the
        resource belongs to another merchant. The machine code is
        `ACCESS_DENIED`. Retrying with the same credential will never succeed.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    StateConflict:
      description: Current state prevents the requested transition.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    ValidationFailed:
      description: The request fails strict syntax or semantic validation.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    RateLimited:
      description: The security operation is temporarily rate limited.
      headers:
        Retry-After:
          description: Suggested delay in seconds when available.
          schema:
            type: integer
            minimum: 1
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    ProviderUnavailable:
      description: >-
        A DropHub dependency is temporarily unavailable and the operation failed
        closed rather than guessing. Retry with bounded exponential backoff and
        jitter.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  headers:
    EntityTag:
      description: Strong numeric entity version for the next state-changing request.
      schema:
        type: string
        pattern: ^"[0-9]+"$
    WwwAuthenticate:
      description: Bearer challenge for an unauthenticated or invalid-token request.
      schema:
        type: string
        example: Bearer
  securitySchemes:
    oauthClientCredentials:
      type: oauth2
      description: >-
        OAuth 2.0 client-credentials flow for external machine-to-machine
        integrations.
      flows:
        clientCredentials:
          tokenUrl: /oauth/token
          scopes:
            shipments:read: Read Merchant-owned shipments
            shipments:write: Create and cancel Merchant-owned shipments
            webhooks:manage: Configure and rotate the merchant's single signed shipment webhook

````