{"openapi":"3.0.3","info":{"title":"BETALL.APP Integration API","version":"1.0.0","description":"Integration API for BETALL.APP customers — manage your contacts and accounts, send SMS with live HLR verification, and send transactional email from your own systems.\n\n## Authentication\nAuthenticate with an **API key** generated from your BETALL Pro account (Settings → Developers / API). Send it as a Bearer token on every request:\n\n```\nAuthorization: Bearer btl_xxxxxxxxxxxxxxxx\n```\n\nKeys are scoped to your organization and inherit your plan limits. A key is shown only once at creation, so store it securely; you can revoke it at any time from your account.\n\n> Account registration and user sign-in are handled on the BETALL.APP website and are intentionally **not** part of this API.","contact":{"name":"BETALL.APP API Support","email":"developers@betall.app"},"license":{"name":"Proprietary — KYO Online Services Ltd"}},"servers":[{"url":"http://localhost:3100","description":"Local gateway"},{"url":"https://api.betall.app","description":"Production"}],"tags":[{"name":"Contacts","description":"Contact records"},{"name":"Accounts","description":"Company / account records"},{"name":"SMS","description":"HLR lookup and SMS sending"},{"name":"Email","description":"Transactional email (Resend) and delivery webhooks"}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"Organization API key generated from your BETALL Pro account (prefix `btl_`)."}},"schemas":{"Error":{"type":"object","properties":{"statusCode":{"type":"integer","example":400},"message":{"type":"string","example":"Validation failed"},"error":{"type":"string","example":"Bad Request"}}},"Contact":{"type":"object","properties":{"id":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string","nullable":true},"position":{"type":"string","nullable":true},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"phoneCountry":{"type":"string","nullable":true,"example":"NO"},"linkedin":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"accountId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"CreateContactRequest":{"type":"object","required":["firstName"],"properties":{"firstName":{"type":"string","minLength":1,"maxLength":80,"example":"Anna"},"lastName":{"type":"string","maxLength":80,"example":"Nilsson"},"position":{"type":"string","maxLength":120,"example":"Head of Procurement"},"email":{"type":"string","format":"email","example":"anna@client.com"},"phone":{"type":"string","maxLength":32,"example":"+4791234567"},"phoneCountry":{"type":"string","minLength":2,"maxLength":2,"example":"NO"},"linkedin":{"type":"string","format":"uri"},"notes":{"type":"string","maxLength":5000},"accountId":{"type":"string","description":"CUID of an existing account"}}},"ContactList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"total":{"type":"integer","example":142},"page":{"type":"integer","example":1},"pageSize":{"type":"integer","example":20}}},"Account":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"industry":{"type":"string","nullable":true},"size":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"example":"SE"},"website":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"CreateAccountRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":160,"example":"Volvo Components AB"},"industry":{"type":"string","maxLength":120,"example":"Manufacturing"},"size":{"type":"string","maxLength":40,"example":"1000-5000"},"country":{"type":"string","minLength":2,"maxLength":2,"example":"SE"},"website":{"type":"string","format":"uri","example":"https://volvo.com"},"notes":{"type":"string","maxLength":5000}}},"HlrLookupRequest":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","minLength":6,"maxLength":20,"example":"+4791234567"}}},"HlrResult":{"type":"object","properties":{"phone":{"type":"string","example":"+4791234567"},"status":{"type":"string","enum":["VALID","INVALID","ROAMING","UNKNOWN"]},"operator":{"type":"string","nullable":true,"example":"Telenor Norge"},"countryCode":{"type":"string","nullable":true,"example":"NO"},"ported":{"type":"boolean","nullable":true}}},"SendSmsRequest":{"type":"object","required":["phone","message"],"properties":{"phone":{"type":"string","minLength":6,"maxLength":20,"example":"+4791234567"},"message":{"type":"string","minLength":1,"maxLength":1600,"example":"Hi Anna, following up on our proposal."},"contactId":{"type":"string","description":"Optional CUID of a contact to link the message to"},"skipHlr":{"type":"boolean","default":false,"description":"Bypass the live HLR check (not recommended)"}}},"SmsSendResult":{"type":"object","properties":{"id":{"type":"string"},"phone":{"type":"string"},"hlrStatus":{"type":"string","enum":["VALID","INVALID","ROAMING","UNKNOWN"]},"deliveryStatus":{"type":"string","enum":["PENDING","BLOCKED","SENT","DELIVERED","FAILED"]},"operator":{"type":"string","nullable":true},"costCredits":{"type":"integer","example":1},"creditsRemaining":{"type":"integer","example":4199}}},"Credits":{"type":"object","properties":{"smsCredits":{"type":"integer","example":4200}}},"SendEmailRequest":{"type":"object","required":["to"],"description":"Provide inline html/text OR a templateKey. A subject is required unless a template supplies one.","properties":{"to":{"type":"string","format":"email","example":"anna@client.com"},"subject":{"type":"string","maxLength":300,"example":"Welcome to BETALL.APP"},"html":{"type":"string","example":"<h1>Welcome {{firstName}}</h1>"},"text":{"type":"string","example":"Welcome to BETALL.APP"},"templateKey":{"type":"string","example":"welcome","description":"Use a stored tenant template"},"locale":{"type":"string","example":"en"},"variables":{"type":"object","additionalProperties":{"type":"string"},"example":{"firstName":"Anna"}},"contactId":{"type":"string","description":"Optional CUID of a contact to link"},"replyTo":{"type":"string","format":"email"}}},"EmailSendResult":{"type":"object","properties":{"id":{"type":"string","description":"EmailLog id"},"providerId":{"type":"string","nullable":true,"description":"Resend message id"},"status":{"type":"string","enum":["QUEUED","SENT","FAILED"]},"live":{"type":"boolean","description":"false when running in mock mode (no API key)"},"errorReason":{"type":"string","nullable":true}}},"EmailTemplateRequest":{"type":"object","required":["key","subject","html"],"properties":{"key":{"type":"string","maxLength":80,"example":"welcome"},"locale":{"type":"string","default":"en","example":"en"},"subject":{"type":"string","maxLength":300,"example":"Welcome {{firstName}}"},"html":{"type":"string","example":"<h1>Welcome {{firstName}}</h1>"},"text":{"type":"string"}}},"EmailLog":{"type":"object","properties":{"id":{"type":"string"},"toEmail":{"type":"string","format":"email"},"fromEmail":{"type":"string","format":"email"},"subject":{"type":"string"},"templateKey":{"type":"string","nullable":true},"status":{"type":"string","enum":["QUEUED","SENT","DELIVERED","DELIVERY_DELAYED","OPENED","CLICKED","BOUNCED","COMPLAINED","FAILED"]},"providerId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}}},"security":[{"apiKeyAuth":[]}],"paths":{"/api/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Full-text search"},{"name":"accountId","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"Paginated contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"401":{"description":"Unauthorized"}}},"post":{"tags":["Contacts"],"summary":"Create a contact","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}}}},"/api/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Contacts"],"summary":"Get a contact","responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Contacts"],"summary":"Update a contact","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactRequest"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}}}},"delete":{"tags":["Contacts"],"summary":"Delete a contact","responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"}}}},"/api/accounts":{"get":{"tags":["Accounts"],"summary":"List accounts","parameters":[{"name":"q","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Accounts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Account"}}}}}}},"post":{"tags":["Accounts"],"summary":"Create an account","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}}}}},"/api/accounts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Accounts"],"summary":"Get an account","responses":{"200":{"description":"The account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}}}},"patch":{"tags":["Accounts"],"summary":"Update an account","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}}}},"delete":{"tags":["Accounts"],"summary":"Delete an account","responses":{"200":{"description":"Deleted"}}}},"/api/sms/hlr-lookup":{"post":{"tags":["SMS"],"summary":"Live HLR lookup","description":"Verifies a number in real time via hlrlookup.com without sending an SMS.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HlrLookupRequest"}}}},"responses":{"201":{"description":"Lookup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HlrResult"}}}}}}},"/api/sms/send":{"post":{"tags":["SMS"],"summary":"Send an SMS","description":"Performs a live HLR check first; invalid numbers are blocked and no credit is charged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendSmsRequest"}}}},"responses":{"201":{"description":"Send result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmsSendResult"}}}},"402":{"description":"Insufficient SMS credits"}}}},"/api/sms/logs":{"get":{"tags":["SMS"],"summary":"SMS logs","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"Paginated SMS logs"}}}},"/api/sms/credits":{"get":{"tags":["SMS"],"summary":"Remaining SMS credits","responses":{"200":{"description":"Credit balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credits"}}}}}}},"/api/email/send":{"post":{"tags":["Email"],"summary":"Send a transactional email","description":"Sends via Resend. Falls back to mock mode (logged, not delivered) when no API key is configured.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequest"}}}},"responses":{"201":{"description":"Send result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSendResult"}}}},"400":{"description":"Validation error"},"404":{"description":"Template not found"}}}},"/api/email/logs":{"get":{"tags":["Email"],"summary":"Email logs","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"Paginated email logs","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailLog"}},"total":{"type":"integer"}}}}}}}}},"/api/email/templates":{"get":{"tags":["Email"],"summary":"List email templates","responses":{"200":{"description":"Templates"}}},"put":{"tags":["Email"],"summary":"Create or update an email template","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTemplateRequest"}}}},"responses":{"200":{"description":"Upserted template"}}}},"/api/email/webhooks/resend":{"post":{"tags":["Email"],"summary":"Resend delivery webhook","description":"Public endpoint. Verifies the Svix signature (svix-id / svix-timestamp / svix-signature headers) and reconciles delivery state (delivered, opened, clicked, bounced, complained).","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","example":"email.delivered"},"data":{"type":"object"}}}}}},"responses":{"200":{"description":"Acknowledged"}}}}}}