Digitally sign an awarded auction
POST/company/bid-auctions/:service_code/sign
Allows the winning carrier to digitally sign the award of an auction.
The signature is performed using a handwritten signature image uploaded by the user.
Objective
To legally formalize the winning carrier's acceptance of the transport,
automatically generating the necessary documents and records for the logistics process.
Automatic Side Effects ⚠️
This endpoint automatically performs the following operations upon completion:
-
Delivery Creation:
- A delivery record associated with the auction is created
- The delivery is initialized with the auction data
- The relationship auction.delivery → delivery._id is established
-
eCMR Generation:
- The eCMR (Digital Consignment Note) document is automatically generated
- The eCMR is associated with the newly created delivery
- It is initialized with the transport data from the auction
-
Status Updates:
- The auction is marked as signed
- signed_by_trucker is set to true
- The date and time of the signature are recorded
-
Entity Relationships:
Auction → Delivery → eCMR
(auction._id) (delivery.auction) (ecmr.delivery)
Signature File Requirements
- Format: JPEG or PNG
- Maximum size: 5MB
- Minimum resolution: 300x100px
- Content: Legible handwritten signature image
Use Cases
- Winning carrier signs the acceptance of an awarded auction
- System automatically generating delivery and eCMR after signing
- Integration with automated transport management workflows
Important Notes
- Only the winning carrier can sign
- The auction must be in the awarded state
- The signature is irreversible and generates permanent records
- The generated documents will be available in the delivery and ecmr endpoints
Signature Flow Diagram:
flowchart LR
A[User signs auction] --> B\{Is winner?\}
B -->|No| C[Error: 403 Forbidden]
B -->|Yes| D\{State = awarded?\}
D -->|No| E[Error: 400 Bad Request]
D -->|Yes| F[Save signature image]
F --> G[Mark: signed_by_trucker = true]
G --> H[Create Delivery]
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"service_code","in":"path","description":"Unique code of the awarded auction.\nFormat: TRANS-XXXXX where XXXXX are 5 digits.","required":true,"example":"TRANS-12345","schema":{"type":"string","pattern":"^TRANS-\\d{5}$","minLength":10,"maxLength":20}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"content":{"multipart/form-data":{"schema":{"type":"object","required":["signImage"],"properties":{"signImage":{"type":"string","format":"binary","description":"Image of the digital signature or identity document. \nAccepted formats: JPEG, PNG (max. 5MB)"}}}}},"required":true}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Signature successfully registered.\nThe auction moves to the 'completed' status and the delivery is created.","content":{"application/json":{"schema":{"type":"object","description":"It represents a transportation auction (public or private) created by a shipper company.\n\n**Complete lifecycle**:\n1. **draft**: Editable draft (visible only to creator)\n2. **planned**: Planned but not yet published\n3. **published**: Visible to carriers, accepting bids\n4. **empty**: Published but no bids received\n5. **awarded**: Winning bid selected (bidWinner assigned)\n6. **approved**: Accepted by carrier, conversion to delivery imminent\n7. **locked**: Closed, not editable (conversion to delivery completed)\n8. **canceled**: Canceled by company\n9. **rejected**: Rejected by carrier\n\n**Auction types**:\n- **Public**: visible to all verified carriers (default)\n- **Private** (is_private=true): visible only to specific carriers (trucker_groups)\n- **Direct**: assigned directly to a carrier without a bidding process\n\n**Model**: `src/features/models/auctions.model.js`\n\n**Controllers**:\n- `src/features/company/auction/controller.js` (CRUD, status)\n- `src/features/company/auction/bid.controller.js` (bid management)\n- `src/features/company/auction/list.controller.js` (listings, filters)\n\n**Services**: `src/features/services/auctions.service.js` (business logic, validations)","properties":{"_id":{"type":"string","description":"Unique MongoDB identifier of the auction. Used as a reference in delivery.auction, auction_bid.auction, notifications.","pattern":"^[a-f0-9]{24}$","example":"64917511ef73c37ccae60bc4"},"service_code":{"type":"string","description":"Unique readable service code, automatically generated upon creation. Format: {prefix}-{timestamp}-{random} e.g., AUC-1729845123-A7B2 **Immutable** - Cannot be changed after creation. Used in: tracking, CMR documents, invoices, customer communication. Indexed for fast searches.","pattern":"^[A-Z0-9-]+$","example":"AUC-1729845123-A7B2"},"custom_code":{"type":"string","description":"Optional custom code assigned by the user (e.g., customer reference). Maximum 128 characters. Can be duplicated between companies (not unique). Used for: integration with external ERP, customer order reference. Editable at any time.","maxLength":128,"example":"PEDIDO-CLIENTE-2025-042"},"status":{"type":"string","enum":["draft","planned","published","empty","awarded","approved","locked","canceled","rejected"],"description":"Current status of the auction in its lifecycle.\n**Valid transitions**: - draft → planned/published (complete required data) - planned → published (manual or scheduled publication) - published → empty (if date_end passes without bids) - published → awarded (upon accepting a bid) - awarded → approved (carrier accepts) - awarded → rejected (carrier rejects) - approved → locked (upon creating delivery) - [any status] → canceled (manual cancellation)\n**Terminal states**: locked, canceled, rejected (non-reversible)\n**Validations per state**: - locked: does not allow editing - published: requires all mandatory fields completed - awarded: requires bidWinner assigned","default":"draft","example":"published"},"date_start":{"type":"string","format":"date-time","description":"Start date/time of the auction (bidding opening). UTC timestamp. Optional - If not specified, publication is immediate. Used in: automated publication scheduling (cron job). Must be < date_end.","example":"2025-10-25T08:00:00.000Z"},"date_end":{"type":"string","format":"date-time","description":"Auction closing date/time (end of bid acceptance). **Required** to publish. UTC timestamp. Upon reaching date_end: cron job closes the auction, notifies if there are bids. Must be > date_start and < etl_date (time for coordination).","example":"2025-10-26T18:00:00.000Z"},"etl_date":{"type":"string","format":"date-time","description":"Expected Time of Loading - Estimated date/time of loading. **Required** for publishing. UTC timestamp. Used in: coordination with carrier, transit time calculation. Must be > date_end (allow time between auction closing and loading). May include a margin with etl_extra_time.","example":"2025-10-27T10:00:00.000Z"},"etl_extra_time":{"type":"number","description":"Extra time allowed for loading in minutes (flexibility margin). Used in: loading window = [etl_date, etl_date + etl_extra_time]. Valid range: 0-99999 minutes. Default: 0. Example: 120 = a 2-hour window to complete the load.","minimum":0,"maximum":99999,"default":0,"example":120},"etd_date":{"type":"string","format":"date-time","description":"Expected Time of Delivery - Estimated delivery date/time. **Required** for posting. UTC timestamp. Must be > etl_date (minimum time = calculated route time). Used in: Customer SLA, penalties for delay, route planning.","example":"2025-10-28T16:00:00.000Z"},"etd_extra_time":{"type":"number","description":"Extra time allowed for unloading in minutes (flexibility margin). Used in: delivery window = [etd_date, etd_date + etd_extra_time]. Valid range: 0-99999 minutes. Default: 0.","minimum":0,"maximum":99999,"default":0,"example":180},"etl_address":{"type":"string","description":"Loading address ID (transport origin). **Required** - Must be a valid ObjectId from the 'address' collection. Verify that the address belongs to the company (owner validation). Used in: route calculation, CMR, pickup coordination. Populated in responses with the complete Address object.","pattern":"^[a-f0-9]{24}$","example":"507f1f77bcf86cd799439011"},"etd_address":{"type":"string","description":"Download address ID (transport destination). **Required** - Must be a valid ObjectId from the 'address' collection. Verify that the address belongs to the company or is public. Used in: route calculation, CMR, delivery coordination. Populated in responses with the complete Address object.","pattern":"^[a-f0-9]{24}$","example":"507f1f77bcf86cd799439012"},"start_price":{"type":"number","description":"Auction starting price in EUR (maximum price the company is willing to pay). **Required** to publish. Carriers bid downwards. Used in: bid validation (bid.price must be ≤ start_price). Minimum: 0, no maximum defined (validate reasonable ranges on the frontend).","minimum":0,"example":850.5},"award_price":{"type":"number","description":"Final awarded price (winning bid price). Null until status=awarded. Copied from bidWinner.price. Used in: billing, margin calculation, savings statistics. Immutable after assignment (audit).","minimum":0,"nullable":true,"example":720},"is_imperial_measure":{"type":"boolean","description":"Measurement system used for weight/dimensions. **false**: Metric system (kg, meters, liters) - Default Europe **true**: Imperial system (pounds, feet, gallons) - USA/UK\nAffects validation and conversion of: cargo_weight, cargo_height, linear_meters. Used in: display with correct units, capacity calculations.","default":false,"example":false},"hscode":{"type":"string","description":"Harmonized System (HS) Code for goods classification. Format: 6-10 digits (may include periods/hyphens). Used in: customs documentation, ADR restrictions, insurance, tariffs. Default: - (not specified). Reference: endpoint /company/hscode for search.","example":"8701.20"},"cargo_weight":{"type":"number","description":"Cargo weight in kilograms (or pounds if is_imperial_measure=true). Range: 0-40000 kg (European truck legal limit). Used in: vehicle capacity validation, cost calculations, route restrictions. Required for cargo_type='full' and 'package'.","minimum":0,"maximum":40000,"example":15000},"linear_meters":{"type":"number","description":"Linear meters occupied in the trailer (measure of cargo length). Range: 0-3500 cm (35 meters, maximum mega-trailer length). Used in: partial load (LTL), validation if it fits in available vehicle. Relevant for cargo_type='pallets' or 'package'.","minimum":0,"maximum":3500,"example":1360},"cargo_height":{"type":"number","description":"Load height in centimeters. Range: 0-4500 cm (45 meters, theoretical limit). Used for: validating vehicles with sufficient clearance, passage restrictions (tunnels). Critical for: refrigerated cargo, oversized cargo.","minimum":0,"maximum":4500,"example":240},"cargo_type":{"type":"string","enum":["pallets","full","package","trailer"],"description":"Type of load that determines transportation method and pricing.\n**pallets**: Palletized load (requires pallets_num, pallets_type) **full**: Full Truck Load (FTL) - Exclusive vehicle **package**: Parcel or loose load LTL (Less Than Truckload) **trailer**: Full trailer (requires plate_full_trailer)\nAffects: required fields, validations, allowed vehicle type.","default":"package","example":"pallets"},"etl_cargo_method":{"type":"string","enum":["back","up","lateral"],"description":"Loading method available at origin address. \n**back**: Rear loading (rear door) - Most common **up**: Top loading (crane, overhead crane) **lateral**: Side loading (side doors, curtains) \nUsed in: matching with carrier vehicle capabilities. Optional - If had_etl_cargo_method=false, any method is accepted.","example":"back"},"had_etl_cargo_method":{"type":"boolean","description":"Indicates whether the loading address has restrictions on the loading method. **true**: Only vehicles with a specific etl_cargo_method can load **false**: No restriction (any method is accepted)\nUsed in: filtering eligible carriers, acceptance validation.","default":false,"example":true},"etd_cargo_method":{"type":"string","enum":["back","up","lateral"],"description":"Download method available at destination address. Same behavior as etl_cargo_method for delivery point.","example":"lateral"},"had_etd_cargo_method":{"type":"boolean","description":"Indicates whether the download address has download method restrictions. Analogous to had_etl_cargo_method for the delivery point.","default":false,"example":false},"is_fresh":{"type":"boolean","description":"Indicate whether the cargo requires refrigeration/temperature control. **true**: Requires a refrigerated vehicle with controlled temperature **false**: Cargo at ambient temperature\nIf is_fresh=true, fresh_cargo_temp must specify the target temperature. Affects: required vehicle type, transport cost, capability validation.","default":false,"example":true},"fresh_cargo_temp":{"type":"number","description":"Target temperature of refrigerated cargo in degrees Celsius. Range: -30°C to +10°C (standard cold storage limits). Used only if is_fresh=true. Examples: -18°C (frozen), 2-4°C (chilled), 8°C (fresh).","minimum":-30,"maximum":10,"default":0,"example":-18},"is_adr":{"type":"boolean","description":"Indicates whether the cargo is dangerous goods (ADR - European Agreement concerning the International Carriage of Dangerous Goods by Road). **true**: Requires ADR certified carrier, approved vehicle, special documentation **false**: Standard cargo without special restrictions\nImpacts: carrier eligibility, route restrictions, increased rates, insurance. Critical for legal compliance.","default":false,"example":false},"pallets_num":{"type":"number","description":"Number of pallets (Europallets or American). Range: 0-66 (theoretical maximum in mega-trailer). **Required** if cargo_type='pallets'. Used in: occupied space calculation, capacity validation, per-pallet pricing.","minimum":0,"maximum":66,"example":24},"pallets_type":{"type":"string","enum":["european","american","none"],"description":"Standard pallet type used.\n**european**: Europallet 1200x800mm (most common in Europe) **american**: Pallet 1200x1000mm (used in USA, some sectors in Europe) **none**: No pallets or non-standard pallets\nAffects: space calculation, load compatibility, trailer load distribution optimization.","default":"none","example":"european"},"description":{"type":"string","description":"Detailed cargo description (optional but recommended). Maximum 2000 characters. Include: product type, packaging, special instructions, restrictions. Used for: communication with carrier, planning, incident resolution. Visible to carriers in auction details.","maxLength":2000,"example":"24 pallets europeos de electrodomésticos. Embalaje retail frágil. Requiere carga cuidadosa y asegurado con cintas."},"info_extra":{"type":"string","description":"Additional information or internal notes (optional). No character limit (consider performance). Used for: company private data, internal references, special instructions. May not be visible to carriers (depends on configuration).","example":"Cliente VIP - Prioridad máxima. Contactar con Juan antes de entregar."},"plate_full_trailer":{"type":"string","description":"Complete trailer registration (required if cargo_type='trailer'). Validation: format according to country (validate with country regex). Used in: asset identification, insurance, tracking, CMR documentation.","pattern":"^[A-Z0-9-]{4,10}$","example":"M-1234-AB"},"user":{"type":"string","description":"Company user ID (company_user) who created the auction. **Required** - Extracted from req.userData._id (m.isLoged middleware). Used in: auditing, notifications, edit permissions. Populated in listings to show the creator's name.","pattern":"^[a-f0-9]{24}$","example":"63d7907cbe76403b35da63df"},"owner":{"type":"string","description":"ID of the company that owns the auction. **Required** - Extracted from the company associated with the authenticated user. Used in: search filters, access permissions, statistics by company. Index for fast queries.","pattern":"^[a-f0-9]{24}$","example":"507f1f77bcf86cd799439013"},"bids":{"type":"array","description":"Array of auction_bid IDs received in this auction. Automatically populated when new bids are created. Ordered by creation date (first bid first). Used in: offer listing, winner selection, statistics.","items":{"type":"string","pattern":"^[a-f0-9]{24}$"},"example":["64917511ef73c37ccae60bc5","64917511ef73c37ccae60bc6"]},"bids_count":{"type":"number","description":"Bid counter (denormalized for performance). Automatically updated when adding/removing bids from the bids array. Used in: sorting by popularity, displaying in listings without populate. Must match bids.length (validate consistency).","minimum":0,"default":0,"example":7},"bidWinner":{"type":"string","description":"ID of the winning bid selected by the company. Null until status='awarded'. Set when accepting a specific bid. Immutable after assignment (audit). Copied to delivery.bidWinner upon conversion. Used to: identify winning carrier, final price (bidWinner.price → award_price).","pattern":"^[a-f0-9]{24}$","nullable":true,"example":"64917511ef73c37ccae60bc5"},"bidAsigned":{"type":"string","description":"Temporarily assigned bid ID (legacy/deprecated). Similar to bidWinner but allows changes (used in old flows). Consider using only bidWinner for new implementations.","pattern":"^[a-f0-9]{24}$","nullable":true},"rejectedBy":{"type":"string","description":"ID of the bid that rejected the assignment. Set when the carrier rejects an awarded auction (status → rejected). Used in: rejection audits, reliability statistics, re-awarding.","pattern":"^[a-f0-9]{24}$","nullable":true,"example":"64917511ef73c37ccae60bc6"},"delivery":{"type":"string","description":"Delivery ID created when auction moves to status='locked'. Null until conversion. 1:1 relationship (one auction generates one delivery). Used for: post-award status tracking, link to CMR documentation.","pattern":"^[a-f0-9]{24}$","nullable":true,"example":"64917511ef73c37ccae60bc7"},"email_end_notified":{"type":"boolean","description":"Flag indicating whether the auction closing email has been sent. **true**: Email already sent (prevents duplicates) **false**: Pending notification. \nSet by a cron job when date_end is reached. Used in: email dispatch control, notification audit.","default":false,"example":true},"sign_image_trucker":{"type":"string","description":"URL of the carrier's digital signature image (CMR documents). Null until signed. Stored in AWS S3. Used in: legal documentation, proof of acceptance of terms.","format":"uri","nullable":true,"example":"https://cargoffer-storage.s3.amazonaws.com/signatures/trucker_sign_123.png"},"sign_image_cia":{"type":"string","description":"URL of the company's digitally signed image (CMR documents). Null until signed. Stored in AWS S3. Used in: legal documentation, proof of cargo compliance.","format":"uri","nullable":true,"example":"https://cargoffer-storage.s3.amazonaws.com/signatures/company_sign_456.png"},"signed_by_company":{"type":"boolean","description":"Indicate whether the company has digitally signed the documentation. Used in: signature workflows, CMR document completeness.","default":false,"example":true},"signed_by_trucker":{"type":"boolean","description":"Indicate whether the carrier has digitally signed the documentation. Used in: signature workflows, CMR document completeness.","default":false,"example":true},"is_faved":{"type":"boolean","description":"Temporary flag (only in request) to create a favorite at the same time as the auction. **true**: Creates an entry in auctions_favorite with data from this auction. **false**: Does not create a favorite.\nNot stored in the auction DB - processed in controller.create()","default":false,"example":false},"trucker_groups":{"type":"array","description":"Array of authorized carrier group IDs (private auctions). Empty for public auctions. Populated for is_private=true. Used in: visibility filtering, restriction of access to details/bids.","items":{"type":"string","pattern":"^[a-f0-9]{24}$"},"example":["64917511ef73c37ccae60bc8"]},"createdAt":{"type":"string","format":"date-time","description":"Auction creation timestamp (automatic mongoose timestamps). Immutable. Used for: chronological ordering, temporal statistics.","example":"2025-10-20T14:30:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"Last modified timestamp (automatic mongoose timestamps). Updated on every save(). Used in: synchronization, change detection.","example":"2025-10-23T09:15:45.000Z"}},"title":"Auction"},"example":{"_id":"64917511ef73c37ccae60bc4","service_code":"TRANS-12345","status":"completed","signed_by_trucker":true,"signed_by_company":true,"delivery":"507f1f77bcf86cd799439100","created_at":"2025-10-25T14:30:00.000Z"}}},"headers":{}},"400":{"description":"Invalid signature data. Possible causes:\n- INVALID_FILE: File is not a valid image\n- FILE_TOO_LARGE: Size exceeds the 5MB limit\n- INVALID_FORMAT: Format not supported (only JPEG/PNG)\n- AUCTION_NOT_SIGNED: The auction does not meet signature requirements","content":{"application/json":{"schema":{"type":"object","required":["status","message"],"properties":{"status":{"type":"integer","description":"HTTP status code","minimum":400,"maximum":599,"example":400},"message":{"type":"string","description":"Error code from the system.\n\nCommon error codes (see listado_errores_http.txt for complete list):\n- NO_TOKEN (401): JWT token not provided\n- TOKEN_NOT_VALID (401): JWT token is invalid or expired\n- NO_ADMIN_ROLE (401): User does not have admin privileges\n- INVALID_PARAMETERS (400): Request parameters are invalid\n- NOT_FOUND (404): Requested resource not found\n- ALREADY_EXIST (401): Resource with same identifier already exists\n- UTC_VALIDATION_FAILED (400): UTC timestamp validation failed\n- INTERNAL_ERROR (500): Unexpected server error occurred\n\nThe message is resolved by `handlerError.getErrorMessage(error)`.","example":"INVALID_PARAMETERS"}},"description":"Standard error response format used across all API endpoints.\n\nAll errors follow the pattern `{status: number, message: string}`.\nThe status code is repeated in both the HTTP response and the body.\n\nError messages are constants defined in the codebase and should be\nhandled on the client side with appropriate user-facing messages.","example":{"status":400,"message":"INVALID_PARAMETERS"},"title":"ErrorResponse"},"example":{"message":"INVALID_FILE","error":"El archivo no es una imagen válida"}}},"headers":{}},"401":{"description":"Unauthorized. Possible causes:\n- NO_TOKEN: Invalid or expired JWT token\n- User is not the auction winner\n- Auction is not in 'awarded' status","content":{"application/json":{"schema":{"type":"object","required":["status","message"],"properties":{"status":{"type":"integer","description":"HTTP status code","minimum":400,"maximum":599,"example":400},"message":{"type":"string","description":"Error code from the system.\n\nCommon error codes (see listado_errores_http.txt for complete list):\n- NO_TOKEN (401): JWT token not provided\n- TOKEN_NOT_VALID (401): JWT token is invalid or expired\n- NO_ADMIN_ROLE (401): User does not have admin privileges\n- INVALID_PARAMETERS (400): Request parameters are invalid\n- NOT_FOUND (404): Requested resource not found\n- ALREADY_EXIST (401): Resource with same identifier already exists\n- UTC_VALIDATION_FAILED (400): UTC timestamp validation failed\n- INTERNAL_ERROR (500): Unexpected server error occurred\n\nThe message is resolved by `handlerError.getErrorMessage(error)`.","example":"INVALID_PARAMETERS"}},"description":"Standard error response format used across all API endpoints.\n\nAll errors follow the pattern `{status: number, message: string}`.\nThe status code is repeated in both the HTTP response and the body.\n\nError messages are constants defined in the codebase and should be\nhandled on the client side with appropriate user-facing messages.","example":{"status":400,"message":"INVALID_PARAMETERS"},"title":"ErrorResponse"},"example":{"message":"NOT_WINNER","error":"El usuario no es el ganador de esta subasta"}}},"headers":{}}}}
>
</StatusCodes>