Some actions are completed only by the person, on DJfindr: accepting an offer, signing its documents and paying, paying a balance or an extension, cancelling a paid booking, and a DJ's refund. For these, the API returns an action link: a single-purpose DJfindr page that your application sends to the person by text, chat or email. The person opens it, verifies their identity and confirms the action on DJfindr. Your application cannot complete these actions on anyone's behalf.
| Link | Endpoint | Scope | Action on the page |
|---|---|---|---|
| Checkout | POST /me/bookings/proposals/{id}/checkout-link | bookings:write | Sign the offer's documents, accept the offer and pay the deposit or the full amount. |
| Payment | POST /me/payments/{id}/pay-link | payments:write | Pay a balance, an extension, or a deposit whose checkout link expired; retry a declined card. |
| Cancellation | POST /me/bookings/proposals/{id}/cancel-link | bookings:write | Cancel a booking with a payment, after reviewing what is refunded and what the DJ keeps. |
| Refund | POST /me/payments/received/{id}/refund-link | payments:write | A DJ refunds a payment they received. amount (minor units) and reason in the body prefill the page. |
| Upload | POST /me/files/upload-link | The :write scope of the file's family | Upload a file of the scope given in the body. Your application then saves it on its record. Signatures and signed documents cannot be uploaded this way. |
| File view | POST /me/files/{id}/view-link | The :read scope of the file's family | Open a private file the person may read. |
Response
Each endpoint returns 201 with the link:
{
"success": true, "error": "", "code": "", "fields": {},
"data": {
"id": "lnk_01K7...",
"purpose": "checkout",
"url": "https://djfindr.com/a#token=...",
"expires_at": "2026-10-27T17:02:11.204Z",
"created_at": "2026-10-20T17:02:11.204Z"
}
}
Treat the URL as a secretSend
urlexactly as returned. The token follows the#, so browsers never send it to a server and it does not appear in analytics or logs. The response is sent withCache-Control: no-store, and DJfindr stores only a hash of the token.
Security
| Behavior | Detail |
|---|---|
| Identity verification | The page does nothing until the browser is signed in to DJfindr as the person the link was created for, with their existing session or a sign-in code sent to their email (and two-factor authentication, when enabled). Anyone else signed in on that browser is told the link is not theirs. |
| No action on open | Opening the page performs no action, so link previews and mail scanners cannot use it. |
| Checked at every step | The link is checked when it is created, and the person's access is checked again on current data before each action on the page. |
Creating links
- No
Idempotency-Key. The response contains the token, which DJfindr never stores alongside a key, so a key that is sent is ignored. Requesting the same link again (same purpose, same record) replaces the previous live link your application created for it. Links created by other applications, or by the person on DJfindr, are not affected. - Refusals. Creating a link returns
409when the action is not possible, with one of the codes below, and404for another person's record. - Limits. 30 links per hour for each person, and 10 per hour for each person and record. Excess requests return
429withRetry-After.
code | Meaning |
|---|---|
not_checkout_ready | The booking has no open offer to accept or pay. |
not_payable | The payment is already paid, or is not one that a payment link can pay. |
withdraw_via_api | Nothing has been paid yet. Withdraw the request with POST /me/bookings/proposals/{id}/withdraw instead. |
withdraw_on_hold | A cancellation link: the booking can't be dropped or canceled online right now. Tell the person to contact DJfindr support; creating the link again will not help until support has looked at it. While this applies, the booking's actions leave out withdraw and its withdraw_blocked carries a message to show as it is. |
payment_disputed | A refund link: the payment has a card dispute that is open, so it cannot be refunded until the dispute closes, or one that was lost, so it cannot be refunded at all. The payment's refundable_amount is 0 meanwhile and its dispute describes the dispute (an inquiry from the card issuer refuses nothing). |
conflict | A refund link: nothing is left to refund. |
Expiry
A link can be used once and expires after at most 7 days.
| Link | Valid until |
|---|---|
| Checkout | The offer expires; after acceptance, the payment deadline. |
| Payment | One day after the payment is due (a deposit's payment deadline, a balance's due date or an extension's event end). |
| Cancellation, refund, upload, file view | 24 hours after creation. |
A link also stops working when:
- The underlying record changes: the DJ edits or withdraws the offer, the booking moves to another state, the payment is paid elsewhere or its amount changes, or the file is deleted.
- The person disconnects your application.
- Your application creates the same link again, or revokes it.
A declined card does not end a checkout or payment link; the person retries on the same page.
A cancellation or refund link created before the booking or payment was put on hold (withdraw_on_hold, payment_disputed) keeps its status of live, but its page cannot complete the action: a cancellation page tells the person it can't be used right now, and a refund page shows that the payment cannot be refunded. If the hold ends before the link expires, the link works again; a lost card dispute's hold on refunds never ends.
Tracking a link
React to events, not to the person reporting that they finished.
| Source | What it tells you |
|---|---|
GET /me/updates | The booking's own events (booking.confirmed, payment.paid, booking.canceled, payment.refunded) describe the outcome. link.completed, sent only to the application that created the link, reports that the link was used. |
GET /me/links/{id} | The link's status, completed_at and result (an upload's file_id; a refund's refund_id, amount and reason). It never returns the URL. Your application can read only the links it created. |
DELETE /me/links/{id} | Revokes a live link your application created (revoked_by_app) and returns its status. A link that already ended is returned unchanged. |
status | Meaning |
|---|---|
live | The link can be used. |
completed | The person completed the action. |
expired | The link reached its expiry time. |
revoked | The link was ended. revoked_reason is replaced, target_changed, app_disconnected, revoked_by_app, revoked_by_person or account. |
Messaging the person
State what the page is for and that it is a DJfindr page, for example: "Open this DJfindr page to sign and pay for your booking with DJ Ada: https://djfindr.com/a#token=..."
Never ask for sign-in codesNever ask the person for a code DJfindr emails them. The code is for signing in to DJfindr, and only the person enters it, on DJfindr.