OpheliaDocs
Search docs⌘K
DashboardCreate an account
End users

Sessions

Connect a person's own Resy account once. Every booking you make for them afterwards is made signed in as them, in their name, with no code.

Sessions need a live API key: connecting texts a real phone. A test key gets 403 live_key_required. Resy is the only provider today.

end_user is your stable id for the person: the same string you send as end_user on POST /v1/bookings. It is scoped to your organization.

1Connect

curl
curl -X POST https://api.opheliaos.com/v1/sessions \
-H "Authorization: Bearer YOUR_LIVE_KEY" \
-H "Content-Type: application/json" \
-d '{
"end_user": "u_42",
"provider": "resy",
"phone": "+15551234567",
"email": "jane.doe.diner@gmail.com",
"name": "Jane Doe"
}'

Resy texts the person a 6-digit code. The call takes about 15–20 seconds and returns 202:

json
{
"id": "sess_21ee94ef92fcafcf9e63597b",
"object": "session",
"provider": "resy",
"owner": { "type": "end_user", "end_user": "u_42", "name": "Jane Doe" },
"state": "awaiting_code",
"next_step": {
"type": "verify_code",
"sent_to": "•••4567",
"expires_at": "2026-09-29T18:39:19Z",
"url": "/v1/sessions/sess_21ee94ef92fcafcf9e63597b/verify"
}
}
FieldNotes
end_user
Required. Your id for the person.
provider
Optional, defaults to resy (the only provider today).
phone
Required. E.164 (+15551234567) or a 10-digit US number. The code is texted here.
email
Required. The email on the person's Resy account. Resy asks for it after the code; we answer it for them.
name
Optional. Kept on the session as owner.name.

If Resy signs the person in without a code, the call returns 200 with the session already active and no next_step.

2Verify

Ask the person for the code and send it before next_step.expires_at (5 minutes):

curl
curl -X POST https://api.opheliaos.com/v1/sessions/sess_21ee94ef92fcafcf9e63597b/verify \
-H "Authorization: Bearer YOUR_LIVE_KEY" \
-H "Content-Type: application/json" \
-d '{ "code": "671737" }'
json
{
"id": "sess_21ee94ef92fcafcf9e63597b",
"object": "session",
"provider": "resy",
"owner": { "type": "end_user", "end_user": "u_42", "name": "Jane Doe" },
"account": { "name": "Jane Doe" },
"state": "active",
"connected_at": "2026-09-29T18:35:02Z",
"last_verified_at": "2026-09-29T18:35:02Z",
"expires_at": "2026-12-28T18:35:02Z"
}

If Resy sends a second code instead of accepting the first, the call returns 202 another_code_sent; verify again with the new code.

3Book

Nothing new: send end_user on POST /v1/bookings. When that person has an active session for the venue's provider, the booking uses it, no code is texted, and the booking carries "session": "sess_…".

If Resy no longer accepts the session, nothing is booked and the booking fails with error_code: "reconnect_required". Connect again, or retry the booking: it goes through Resy's sign-in and keeps the new session.

4Check for a card on file

Some Resy venues need a card on the person's account to book. Ask before you try:

curl
curl https://api.opheliaos.com/v1/sessions/sess_21ee94ef92fcafcf9e63597b/card \
-H "Authorization: Bearer YOUR_LIVE_KEY"
 
# or by your own id for the person (provider defaults to resy)
curl "https://api.opheliaos.com/v1/sessions/card?end_user=u_42" \
-H "Authorization: Bearer YOUR_LIVE_KEY"
json
{
"object": "card_check",
"session": "sess_21ee94ef92fcafcf9e63597b",
"provider": "resy",
"owner": { "type": "end_user", "end_user": "u_42", "name": "Jane Doe" },
"account": { "name": "Jane Doe" },
"has_card": true,
"checked_at": "2026-09-30T18:40:02Z"
}

We sign in with the person's session and read their payment methods; nothing is changed. The answer is yes or no: no card details are returned or kept. A check takes about 15–30 seconds, so run it when it matters rather than on every screen.

If Resy no longer accepts the session, the answer is 409 reconnect_required (never has_card: false) and the session becomes expired. No session for that end_user is 404 session_not_found.

Whose account

owner is who the session is for: your end_user and the name you sent. account.nameis the name on the person's own Resy account, read when they connect and on every card check, so you can see whose account a session signs in to. It is absent until we have read it, and removed on disconnect.

Endpoints

POST/v1/sessionsConnect a person (texts them a code).
POST/v1/sessions/{id}/verifySend the code. The session becomes active.
GET/v1/sessionsList sessions. Filter with ?end_user= &provider= &state=.
GET/v1/sessions/{id}One session.
DELETE/v1/sessions/{id}Disconnect. The session is destroyed.
GET/v1/sessions/{id}/cardDoes their account have a card on file?
GET/v1/sessions/cardThe same, by ?end_user= (&provider=, default resy).

state is one of awaiting_code, active, expired, disconnected. expires_at is the expiry Resy set; after it the session is not used. Your organization's own concierge sessions appear in the same list with owner.type: "organization"; they are read-only here (disconnecting or card-checking one is 409 organization_session).

Rate limits, per organization per 5 minutes: connect and verify share session_connect (20); card checks session_card (30). See Errors for the 429 shape.

Errors

HTTPerror_codeMeaning
400
end_user_required, phone_invalid, email_required, code_required, invalid_json, invalid_state
Fix the request.
400
invalid_code
Resy rejected the code. Check it, or connect again.
202
another_code_sent
Resy sent a new code. Verify again with that one.
403
live_key_required
Use a live key.
404
session_not_found
No such session (or none for that end_user).
409
session_not_active
The session is expired or disconnected. Connect again.
409
reconnect_required
Resy turned the session away during a card check. Connect again.
409
not_awaiting_code
Nothing is waiting for a code. Connect again.
409
organization_session
That is one of your organization's own sessions; manage it in the dashboard.
410
code_expired
The 5 minutes passed. Connect again.
422
provider_unsupported
Only resy today.
429
code_recently_sent
A code went out under 30 seconds ago. Wait.
502
provider codes, card_check_failed
Resy's sign-in or the card check failed. Retry.
503
sessions_unavailable
Sessions are not available right now. Retry later.

We never return, log or store a session unencrypted.