BillyDocumentation

Transfer a ticket

Hands a ticket to whoever bought it on a resale marketplace. The ticket keeps its `ticketId` — nothing is voided and nothing is re-issued — but its `qrCode` is regenerated, so the seller's code stops opening the door the moment this returns. Billy sends no email: the response carries the new code, and delivering it to the new holder is yours to do. `attendee` is optional. Sent, it also changes the holder — whether or not the offer collects attendee details of its own; left out, only the code rotates. The response carries the holder as the ticket now has them. `attendee` carries the person's own details only — no `additionalFields`, and unknown keys are rejected with a 400. A resale marketplace knows who bought the ticket; it has no way to have asked the organizer's own questions, and an answer it invented would reach the attendance list as though the buyer had given it. Those questions stay unanswered until the buyer answers them, and the details sent here are accepted as the partial picture they are — there is no form here for them to fail. **This endpoint is not idempotent, and there is no `Idempotency-Key`.** Every call rotates the code afresh, so calling it twice retires the code the first call returned. Retry a request whose response you never saw — a timeout, a dropped connection — and the code you already delivered to the new holder stops scanning, silently, with nothing to tell you until they are refused at the door. Treat a transfer whose outcome you are unsure of as a read: fetch the ticket and compare its `qrCode` before sending anything.

Preview release

This operation is only available on the preview release target — send Billy-API-Version: preview to reach it. Preview has no stability promise: its routes and payloads can change without notice, so pin a dated release before you depend on one. The playground below sends a real POST request to the live API with your own key, and will create or modify actual data.
POST
/v1/tickets/{ticket_id}/transfer

Hands a ticket to whoever bought it on a resale marketplace. The ticket keeps its ticketId — nothing is voided and nothing is re-issued — but its qrCode is regenerated, so the seller's code stops opening the door the moment this returns. Billy sends no email: the response carries the new code, and delivering it to the new holder is yours to do.

attendee is optional. Sent, it also changes the holder — whether or not the offer collects attendee details of its own; left out, only the code rotates. The response carries the holder as the ticket now has them.

attendee carries the person's own details only — no additionalFields, and unknown keys are rejected with a 400. A resale marketplace knows who bought the ticket; it has no way to have asked the organizer's own questions, and an answer it invented would reach the attendance list as though the buyer had given it. Those questions stay unanswered until the buyer answers them, and the details sent here are accepted as the partial picture they are — there is no form here for them to fail.

This endpoint is not idempotent, and there is no Idempotency-Key. Every call rotates the code afresh, so calling it twice retires the code the first call returned. Retry a request whose response you never saw — a timeout, a dropped connection — and the code you already delivered to the new holder stops scanning, silently, with nothing to tell you until they are refused at the door. Treat a transfer whose outcome you are unsure of as a read: fetch the ticket and compare its qrCode before sending anything.

Authorization

HTTPBearer
AuthorizationBearer <token>

API key authentication. Format: Bearer billy:o:<organization_id>:<api_key>

Example: Bearer billy:o:yyyyyyyyyyyyyyyy:xxxxxxxxxxxxxxxxx

In: header

Path Parameters

ticket_id*Ticket Id

Header Parameters

Billy-API-Version*string

Requested API version. Current context: preview.

Default"preview"

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Request body for POST /v1/tickets/{ticket_id}/transfer.

attendee is optional: left out, the transfer rotates the code and leaves the holder as they were. The body itself may therefore be {}.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/tickets/string/transfer" \  -H "Billy-API-Version: preview" \  -H "Content-Type: application/json" \  -d '{}'
{  "ticketId": "a385b297-a4d0-47fd-ab18-dd5bb56eebc3",  "eventId": "34280fd9-3f2f-4831-90ec-d76ac0cb7c8b",  "invoiceReference": "FR12345678901",  "status": "FULFILLED",  "offerId": "a9e51970-77db-4439-b1d8-7432203e04a2",  "offerName": "VIP",  "issuedAt": "2025-02-10T14:22:05.000Z",  "updatedAt": "2025-02-10T14:22:05.000Z",  "cancelledAt": null,  "eventSessionId": "6095dfdb-aa90-4d18-b0cb-3f9ef4b82238",  "eventSessionStartAt": "2025-03-21T19:30:00.000Z",  "seatingInfo": {    "blocName": "Bloc A",    "seatRow": "B",    "seatNumber": "12"  },  "qrCode": "TCKT-9F2K-77QX",  "issuanceChannel": "ONLINE_EVENT_SHOP",  "salesChannelName": "Default online store",  "salesChannelId": "5ad8d09e-c789-49e6-a8f8-1434f880beeb",  "orderId": "b2c8c0d4-1f2e-4a3b-9c6d-2e7f1a8b3c4d",  "orderNumber": "QASQTFGU",  "priceLabel": "PLEIN TARIF",  "listPrice": 120,  "finalPaidPrice": 100,  "vat": 20,  "currency": "EUR",  "transferable": true,  "customer": {    "customerId": "eecedea0-e9ed-44d9-9fbf-6cc24a2b2bf4",    "firstName": "Claire",    "lastName": "Dupont",    "email": "claire.dupont@email.com",    "phone": "+33612345678",    "birthDate": "1990-05-17",    "address": {      "companyName": null,      "addressLine1": "12 rue de la Paix",      "addressLine2": null,      "city": "Paris",      "postalCode": "75001",      "countryCode": "FR"    },    "additionalFields": [      {        "name": "tshirt-size",        "type": "SINGLE_SELECT",        "value": "L"      },      {        "name": "dietary",        "type": "MULTI_SELECT",        "value": [          "vegetarian"        ]      }    ]  },  "attendeeForm": {    "formId": "frm_01BCDEFGHIJKLMNO",    "formVersion": 4,    "submittedAt": "2025-02-11T09:03:12.000Z"  },  "customerForm": {    "formId": "frm_01ABCDEFGHIJKLMN",    "formVersion": 2,    "submittedAt": "2025-02-10T14:22:05.000Z"  },  "attendee": {    "firstName": "Alice",    "lastName": "Martin",    "email": "alice.martin@email.com",    "phone": null,    "birthDate": null,    "address": null,    "additionalFields": []  }}