Create Order

Submit a new order with product selection, payment details, and customer information.

text
POST /orders

This endpoint requires an HMAC signature (see Authentication). Request bodies are strictly validated: unknown fields are rejected with a 400.

Request Body

json
{
	"products": [
		{
			"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
			"productTypeId": 1,
			"quantity": 1,
			"vehiclePlate": "AB123CD",
			"vehicleCountryIsocode": "AT",
			"vehicleCategoryId": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
			"startAt": "2026-04-01T00:00:00.000Z",
			"endAt": "2026-04-10T23:59:59.000Z",
			"driverFirstname": "John",
			"driverLastname": "Doe"
		}
	],
	"payment": {
		"method": "saved_card",
		"savedCardId": "3f2b1a0c-9d8e-7f6a-5b4c-3d2e1f0a9b8c",
		"returnUrl": "https://yourapp.com/payment/callback"
	},
	"customer": {
		"email": "john.doe@example.com",
		"firstName": "John",
		"lastName": "Doe",
		"phone": "+43123456789"
	},
	"address": {
		"countryIsocode": "AT",
		"city": "Vienna",
		"addressLine": "Mariahilfer Strasse 1",
		"postalCode": "1060",
		"taxNumber": "ATU12345678",
		"companyName": "Doe GmbH"
	},
	"idempotencyKey": "unique-order-key-12345",
	"externalReference": "YOUR-ORDER-REF-001",
	"callbackUrl": "https://yourapp.com/webhooks/vignetim"
}

Products Array

1 to 50 items per order.

FieldTypeRequiredDescription
productIdstringYesTicket UUID, eSIM package ID, or insurance product slug (max 255 chars)
productTypeIdintegerYesProduct type: 1 = TICKET (vignette), 2 = ESIM, 4 = INSURANCE, 5 = FINES
quantityintegerYesNumber of units (min 1)
vehiclePlatestringConditionalVehicle license plate, max 20 chars (vignettes)
vehicleCountryIsocodestringConditionalVehicle registration country ISO code, max 5 chars (vignettes)
vehicleCategoryIdstringConditionalVehicle category ID, max 100 chars (vignettes)
startAtISO 8601ConditionalValidity start date
endAtISO 8601ConditionalValidity end date
driverFirstnamestringNoDriver first name, max 100 chars (required by some countries)
driverLastnamestringNoDriver last name, max 100 chars (required by some countries)

productTypeId value 3 (SERVICE) is internal and not orderable through the Partner API.

Payment Object

FieldTypeRequiredDescription
methodstringYessaved_card or wallet
savedCardIdUUIDConditionalRequired when method is saved_card. Must be a card vaulted for your organization; unknown or foreign card IDs return 404
returnUrlstringNoHTTPS URL for redirect-based flows

No raw card data is ever accepted on this API.

Payment Routing

  • saved_card -- Charges a card previously vaulted through the partner dashboard card registration flow (a one-time 3D Secure verification). The charge is processed by NestPay. See Saved Cards.
  • wallet -- Debits your prepaid EUR organization wallet. The wallet is funded by bank transfer, posted by the Vignetim back office. If the balance does not cover the order, the API returns a 422 with code INSUFFICIENT_WALLET_BALANCE (see Wallet).

Customer Object

FieldTypeRequiredDescription
emailstringYesCustomer email address
firstNamestringYesCustomer first name, max 100 chars
lastNamestringYesCustomer last name, max 100 chars
phonestringNoCustomer phone number, max 20 chars (E.164 format recommended)

Instead of the inline customer object you can send a top-level customerLinkId (UUID of a stored customer link) and the customer details are filled from the stored record. Provide exactly one of customer or customerLinkId; sending both or neither returns a 400.

Address Object

FieldTypeRequiredDescription
countryIsocodestringYesCountry ISO code, max 5 chars
citystringYesCity name, max 100 chars
addressLinestringYesStreet address, max 300 chars
postalCodestringNoPostal/ZIP code, max 20 chars
taxNumberstringNoTax/VAT number, max 50 chars (B2B invoicing)
companyNamestringNoCompany name, max 200 chars (B2B invoicing)

Additional Fields

FieldTypeRequiredDescription
customerLinkIdUUIDNoStored customer link ID; replaces the inline customer object (mutually exclusive)
idempotencyKeystringNoUnique key to prevent duplicate orders, max 255 chars (strongly recommended)
externalReferencestringNoYour internal order reference for tracking, max 255 chars
callbackUrlstringNoHTTPS URL for payment callbacks. Falls back to payment.returnUrl when omitted

All URLs must be HTTPS.

Example Request

With method: 'wallet', drop savedCardId from the payment object.

POST/v2/partners/orders
API_KEY="your-api-key"
API_SECRET="your-api-secret"

# Signing key = SHA-256 hex digest of your API secret
# $NF, not $2: OpenSSL prints "SHA2-256(stdin)= <hash>" but LibreSSL (the macOS
# default) prints the bare hash, where $2 is empty β€” that yields an empty signing
# key and a 401 with nothing to indicate why.
SIGNING_KEY=$(echo -n "${API_SECRET}" | openssl dgst -sha256 | awk '{print $NF}')

TIMESTAMP=$(date +%s)
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')
METHOD="POST"
REQ_PATH="/v2/partners/orders"

# No request body: sign an empty body string.
BODY=""

MESSAGE="${TIMESTAMP}.${NONCE}.${METHOD}.${REQ_PATH}.${BODY}"

SIGNATURE=$(echo -n "${MESSAGE}" | \
  openssl dgst -sha256 -hmac "${SIGNING_KEY}" | \
  awk '{print $NF}')

curl -X POST "https://api.vignetim.com${REQ_PATH}" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}"

Response

201 Created

The same shape is returned for live orders, sandbox orders, and idempotency replays:

json
{
	"transactionId": "b6f0e2d4-8c1a-4e5f-9b3d-7a2c4e6f8a0b",
	"status": "COMPLETED",
	"statusLabel": "COMPLETED",
	"redirectUrl": "https://pay.vignetim.com/3ds/verify/abc123"
}
FieldTypeDescription
transactionIdstringPayment transaction ID (bare UUID; sandbox_<16hex> in sandbox)
statusstringPayment transaction status, e.g. COMPLETED, FAILED, PENDING_3D
statusLabelstringSame as status; human-readable payment status
orderIdstringCreated order ID. Currently returned for sandbox orders only; for live orders, list by externalReference or wait for the webhook
redirectUrlstringPresent for redirect-based flows; send the customer here to complete the payment
sandboxbooleantrue when the order was created with a TEST key

Error Responses

StatusCause
400Validation failure, unknown fields, missing savedCardId for saved_card, or daily order limit exceeded
403Missing/invalid signature, or your organization is not authorized to place orders
404savedCardId not found or not owned by your organization
409A request with this idempotency key is already in flight
422Insufficient wallet balance (INSUFFICIENT_WALLET_BALANCE)
429Order creation rate limit (10/min) exceeded

Idempotency

Order creation is idempotent per (organization, idempotencyKey):

  • The first request with a key claims it atomically before any work starts.
  • A concurrent request with the same key while the first is still processing returns 409 with A request with this idempotency key is already in flight.
  • Once the first request completes, its result is cached and replayed for 24 hours: retries with the same key return the original response without creating a new order or charging again.
  • If a request fails before payment was initiated (validation error, missing card, insufficient balance, daily limit), the claim is released immediately and the key can be retried right away.
  • If a request fails after payment was initiated, the claim is held for up to about 5 minutes (duplicates get 409 in that window) to protect against double charges; after that, retries with the same key are deduplicated by the payment layer.

Always generate one idempotency key per logical order and reuse it for all retries of that order.