How to get started with Teya?

A guide for a new merchant who sells one subscription product with two prices, for example a monthly and a yearly price, takes cards through the new Teya gateway and sells either on an Áskell hosted payment page or in a widget on their own website.

Which route fits

Choose the payment page unless you have a backend and someone who can add code. Steps 1–3 are the same for both routes, and you can add the widget later.

Route A: Payment page

Route B: Widget

Where the buyer pays

On an Áskell page that you link to

On your own website

Programming

None

A backend creates a session with a secret API key

Website platform

Any website, including Wix and Squarespace

A website with its own server, for example Node, PHP or Python

Apple Pay

Possible on your own subdomain, enabled by Áskell

No

Steps

1, 2, 3 and A

1, 2, 3 and B

Before you start

  • An Áskell account. You can sign up at askell.is/signup.

  • An online payments agreement with Teya and a Teya ID that can sign in to the Teya Business Portal.

  • Confirmation from Teya that the store is allowed to save cards and take recurring merchant-initiated payments.

  • The product name, the two prices and whether they include VAT.

  • The address of your website and of your terms.

  • For the widget: a server (backend) that can keep a secret API key, and someone to add the code, a developer or an AI tool.

Step 1: Connect the Teya gateway

You do not type in any keys. Áskell opens Teya, you sign in and pick a store, and Teya sends the connection details straight to Áskell.

  1. In the Áskell dashboard: Settings → Payment processors → Add a payment processor.

  2. Name: for example “Teya cards”. Buyers do not see the name.

  3. Type: choose Greiðslukort (Teya). This option is shown in Icelandic in every language. Do not choose “Greiðslukort (Saltpay/Teya RPG)”, which is the old gateway.

  4. Currencies: ISK is selected by default. Only add a currency that your Teya store accepts.

  5. Leave the Connect to the Teya staging environment switch off. It is only for a separate test store at Teya.

  6. Click Save. You land on the payment processor’s page with the Teya connection panel, marked Not connected.

  7. Click Connect with Teya. Teya opens in a new tab.

  8. Sign in with your Teya ID and choose the store that should receive the payments.

  9. Go back to the Áskell tab. Within a few seconds it shows Connected and “Store: … · Connected on …” with the store’s Teya ID.

Finish steps 7–9 within 10 minutes. Otherwise “Teya has not confirmed the connection yet” appears and you click Connect with Teya again.

Staging or production: you cannot switch while the payment processor is connected. Create a separate payment processor for each environment instead. The switch applies as it was last saved, so click Save before you connect.

Apple Pay is off by default and merchants cannot turn it on themselves. It is only offered on payment pages on your own subdomain, not in the widget. Contact Áskell if you want to offer it.

Step 2: Create the product and its two prices

You create one product and add both prices to it in the same window. The example uses 1990 kr. a month and 19900 kr. a year.

VAT first, if you charge VAT: Settings → Tax rates → Add a tax rate. Turn on Default for account and set Rate percent and Calculation mode in the version. Choose Inclusive if the prices you enter include VAT. The default is Exclusive, which adds VAT on top: 1990 kr. becomes 2468 kr. with 24% VAT. With no tax rate, no VAT is calculated.

  1. Contracts → Catalog → New catalog product.

  2. Product name: the name buyers see, for example “Newsletter Plus”.

  3. Electronic only: leave it on unless you ship something. When it is off, the checkout asks for an address.

  4. Reference: leave it empty or make it readable. The widget shows the reference under each price.

  5. Tax policy: “Use account default tax”, or “Do not apply tax” if no VAT applies.

  6. Optional: Other settings → Add setting → Trial period. The trial applies to both prices.

  7. The first price card under Prices is open. Fill it in and click Save price:

    • Unit amount: 1990, digits only, no dot or “kr.”

    • Currency: ISK

    • Price description: “Monthly subscription, billed monthly”

    • Billing type: Recurring

    • Interval: Months, Interval count: 1

  8. Click Add price, fill it in the same way and click Save price again. The differences are:

    • Unit amount: 19900

    • Price description: “Yearly subscription, billed yearly”

    • Interval: Years, Interval count: 1

  9. When both prices are saved, click Save at the bottom of the window. The prices are not saved until then, and Save is disabled while a price card is open.

Do not skip the price description, even though the field is optional. The widget shows the product name and the amount for each price, but not the billing interval. Without descriptions the two prices look the same apart from the amount.

Leave the other price card settings as they are. Do not use Add version (a scheduled price change) or Customer chooses the amount. The price’s currency must be in Currencies on the Teya payment processor.

Step 3: Create and activate a sales channel

The sales channel decides what is sold, where, and through which payment processor. Both the payment page and the widget need an active sales channel.

  1. Contracts → Sales channels → New sales channel.

  2. Sales channel name: for example “Website subscription”.

  3. Reference: a short word with letters, for example askrift. Not digits only. The developer needs this value for the widget.

  4. Allowed origins: your website’s address without anything after the domain, for example https://www.minnvefur.is, then press Enter. Also add https://minnvefur.is if the site answers without www. This is needed even if you only use a payment page, otherwise the channel cannot be activated.

  5. Offer availability → Add a product, price or bundle → choose “Your product: Whole product”. Both prices are then on offer.

  6. Price selection: choose Customers pick exactly one price per purchase. Otherwise a buyer can buy the monthly and the yearly subscription in one purchase.

  7. Default quantity limits: turn it on and set Default maximum to 1. Otherwise a buyer can buy more than one subscription in one purchase.

  8. Payment collection → Add a payment processor → choose the Teya payment processor from step 1. It becomes the Default.

  9. Checkout behavior:

    • Customer reference: “Icelandic ID number” if the buyer should enter a kennitala.

    • Terms URL: the address of your terms. The buyer then has to accept them.

  10. Click Save. The channel is saved as Draft and the window stays open.

  11. Change the status next to the title from Draft to Active. If the status picker is disabled, the form has unsaved changes, so save first.

If activation is refused, the channel is missing an origin, a payment processor or a product. Leave Advanced unchanged.

Route A: Payment page

The payment page takes the product, the prices and Teya from the sales channel. The page itself has no product or payment processor choice.

  1. Payment pages → New payment page. If there is no page theme yet, Áskell asks you to create one first. Fill it in and click Continue.

  2. Fill in the required fields:

    • Name: only visible to you.

    • Title: the heading buyers see.

    • Page content and Image: both are required.

    • Theme and Layout: choose the theme and List.

  3. Sales channel: choose the sales channel from step 3. It is only listed when it is Active.

  4. Customer reference field settings: Icelandic ID number.

  5. Terms link (optional): the address of your terms.

  6. Redirect link (optional): a page on your website that buyers go to after the purchase, for example “Thank you”.

  7. Turn on Active at the top of the form. New pages are inactive.

  8. Click Save. The page opens in the window.

  9. Click the magnifying glass at the top of the window (Preview). The page opens in a new tab, and the address in the browser is your link, in the form https://askell.is/public/payments/<number>/, or on your own subdomain if one is set up.

  10. Put the link on a button or link on your website.

The buyer clicks one of the price cards, which show “Subscription · period”, fills in name, kennitala, email and phone, and pays by card in the Teya window. Do not put the payment page in an iframe, it is not shown there. Use an ordinary link.

You can prefill fields by adding to the address, for example ?email=jon@example.is&name=Jón%20Jónsson. Fields filled in this way are locked. See Payment pages.

Route B: Widget on your own website

The widget (askell.js) shows the checkout on your own website. Your server first creates a short-lived session with a secret API key, and the browser only gets the session token.

How the checkout works

  1. The buyer opens your subscription page.

  2. Your server creates a session at Áskell with the secret key and gets a token back.

  3. The page loads askell.js and shows the widget with the token.

  4. The buyer picks a price, fills in their details, accepts the terms and enters a card in the Teya window.

  5. The widget calls onSuccess. Your server confirms the purchase with Áskell before granting access.

Setup

  1. Settings → API keys → Create a new API key, with a name such as “Website”, then Save.

  2. Copy the Private Key right away, it is only shown once. Keep it in an environment variable on the server, for example ASKELL_SECRET_KEY. Never in HTML, JavaScript or git.

  3. Check that the page’s domain is listed exactly in the sales channel’s Allowed origins. https://www.minnvefur.is and https://minnvefur.is are two different origins, and there must be no trailing slash.

  4. Give the developer or the AI tool the prompt below, together with the sales channel’s Reference.

Minimal example

The server creates the session:

POST https://askell.is/api/v2/checkout-sessions/
Authorization: Api-Key <ASKELL_SECRET_KEY>
Content-Type: application/json

{"sales_channel": "askrift", "contract_reference": "notandi-123"}

The response contains "token". The page then shows the widget with it:

<div id="askell-checkout"></div>
<script src="https://cdn.askell.is/js/dist/askell.js"></script>
<script>
  Askell.mountCheckout("#askell-checkout", {
    sessionToken: "TOKEN_FRA_THJONINUM",
    language: "is",
    onSuccess() { window.location.href = "/takk"; },
    onError(error) { console.error(error); }
  });
</script>

Confirming on the server

Do not grant access based on onSuccess alone. The server fetches GET /api/v2/checkout-sessions/<token>/ and checks that status is completed. It then fetches the contract in contract_id with GET /api/v2/subscription-contracts/<contract_id>/ and grants access when service_active is true. To hear about renewals and cancellations: Settings → Webhooks, event subscription_contract.*, see Webhooks.

contract_reference is your own reference, for example a user ID or an order number. It ends up on the contract and in every webhook. Do not send customer_reference unless the customer already exists in Áskell, because the widget asks for the kennitala itself. See Embedded checkout.

Testing before going live

Test first with the test gateway on a separate test sales channel, so that no real payment takes place. Then finish with one real purchase through Teya.

Test setup, once

  1. Settings → Payment processors → Add a payment processor, Type: “Credit card (for testing simulated 3D secure flow)”.

  2. Create a second sales channel as in step 3, with the Reference askrift-prof and the test gateway instead of Teya. The developer adds http://localhost:3000 or their own domain to Allowed origins.

  3. Payment page: create a separate test payment page that uses the test sales channel, and never put it on your website. Do not switch the sales channel on a page that is already linked from your website, because with the test gateway anyone can buy without paying.

  4. Widget: the developer sends "sales_channel": "askrift-prof".

With the test gateway, any card number with 11–19 digits works. CVV 322 skips the 3-D Secure step, CVV 400 makes the registration fail, and CVV 500 registers the card but every charge on it fails.

Test this

  • Both prices are shown, each with its description, and only one of them can be chosen.

  • The amount on the review step is right, with VAT as you intended.

  • A purchase with CVV 322 succeeds and a contract appears under Contracts → Contracts with the right price.

  • A purchase with CVV 400 shows an error and does not create an active contract.

  • The buyer lands on the right page after the purchase.

  • Widget: the server confirms the purchase and grants access, and the webhook arrives. Webhooks are not delivered to localhost, so use a public address, for example through ngrok.

Going live

  1. Payment page: link to the real page that uses the askrift sales channel. Widget: change sales_channel back to askrift.

  2. Buy a subscription once with your own card through Teya.

  3. Check that the contract is active and that the payment shows in the Teya Business Portal.

  4. Open Transactions or Billing runs, choose the payment and click Refund. Then cancel the subscription under Contracts → Contracts.

  5. Set the test sales channel to Archived and delete the test payment page.

Prompt for an AI tool

Copy all of the text below into ChatGPT, Claude, Cursor or a similar tool. First fill in the brackets under MÍNAR UPPLÝSINGAR (my details). The prompt is in Icelandic, which these tools understand; add “Answer in English” at the end if you prefer. It forbids the tool from inventing endpoints other than the ones it should use.

Þú ert reyndur vefforritari. Hjálpaðu mér að setja áskriftarkaup frá Áskeli (askell.is) inn á vefinn minn með innfellda widgetinu askell.js. Ein vara er í boði með tveimur verðum (mánaðar og árs) og kaupandi velur annað þeirra í widgetinu. Kortagreiðslur fara gegnum Teya, sem er tengt í Áskeli og birtist sjálfkrafa inni í widgetinu. Þú skrifar engan Teya-kóða.

MÍNAR UPPLÝSINGAR:
- Vefkerfi og bakendi: [t.d. Next.js, Express, Laravel, Django, WordPress/PHP]
- Síðan sem widgetið á að vera á: [t.d. https://www.minnvefur.is/askrift]
- Takk-síða eftir kaup: [t.d. /takk]
- Auðkenning notenda: [t.d. innskráðir notendur með user.id, eða engin innskráning]
- Tilvísun sölurásar: askrift (prófunarsölurás: askrift-prof)

1. BAKENDALEIÐ SEM STOFNAR LOTU, t.d. POST /api/askell/session
- Kallar á POST https://askell.is/api/v2/checkout-sessions/
- Hausar: "Authorization: Api-Key <ASKELL_SECRET_KEY>" og "Content-Type: application/json"
- Body: {"sales_channel": <ASKELL_SALES_CHANNEL>, "contract_reference": <notandanúmer eða pöntunarnúmer, mest 128 stafir, engin komma>, "expires_in_seconds": 1800}
- Má bæta við "metadata": {...} með mínum eigin gögnum.
- Sendu EKKI "customer" eða "customer_reference". Widgetið spyr kaupandann sjálft um kennitölu, nafn, netfang og síma.
- Svar 201 inniheldur "token". Geymdu það á þjóninum með notandanum eða pöntuninni (t.d. í session) og skilaðu vafranum aðeins {"sessionToken": token}.
- Stofnaðu nýja lotu í hvert sinn sem síðan er opnuð. Lota er skammlíf og nýtist aðeins einu sinni.
- ASKELL_SALES_CHANNEL kemur úr umhverfisbreytu svo ég geti skipt á milli askrift-prof og askrift.

2. FRAMENDI Á SÍÐUNNI
- <div id="askell-checkout"></div>
- <script src="https://cdn.askell.is/js/dist/askell.js"></script>, hlaðið beint af þessari slóð. Ekki afrita skrána eða setja hana í bundle, hún sækir askell.css sjálf úr sömu möppu.
- Sæktu sessionToken frá leið 1 og kallaðu svo á:
  const handle = window.Askell.mountCheckout('#askell-checkout', {
    sessionToken,
    language: 'is',
    title: 'Veldu áskrift',
    onSuccess(result) { /* kalla á leið 3, svo á takk-síðuna */ },
    onError(error) { /* error.status og error.payload geta fylgt */ },
  });
- Ekki senda baseUrl (sjálfgefið er https://askell.is). Ekki senda "offer", því þá getur kaupandi ekki valið á milli verðanna.
- mountCheckout skilar { destroy() }. Í React, Vue eða annarri SPA: kallaðu á handle.destroy() þegar íhluturinn hverfur, og gættu þín á tvöfaldri keyrslu í React StrictMode.
- onSuccess: treystu því ekki einu og sér. Kallaðu á leið 3 og sendu kaupandann svo á takk-síðuna.
- onError: sýndu vinalega villu á íslensku og hnapp sem sækir nýja lotu og sýnir widgetið aftur.

3. BAKENDALEIÐ SEM STAÐFESTIR KAUP, t.d. POST /api/askell/verify
- Notar token lotunnar sem er geymt á þjóninum, ekki gildi frá vafranum.
- GET https://askell.is/api/v2/checkout-sessions/<token>/ með sama Authorization-haus. Krefstu þess að status sé "completed" og lestu contract_id.
- GET https://askell.is/api/v2/subscription-contracts/<contract_id>/. Veittu aðgang aðeins ef service_active er true. Vistaðu contract_id, customer_id og items[].price_id, sem segir hvort verðið var keypt.
- Ef service_active er enn false, reyndu aftur nokkrum sinnum á um 30 sekúndum. Vefkrókurinn í lið 4 klárar málið annars.

4. VEFKRÓKUR, t.d. POST /api/askell/webhook
- Áskell sendir JSON {"event", "ref", "sender", "data"}, þar sem data er samningurinn.
- Staðfestu hausinn Hook-HMAC áður en nokkuð annað er gert: base64(HMAC-SHA512(ASKELL_WEBHOOK_SECRET, hrá bæti body)), borið saman í föstum tíma. Notaðu hráa body-ið, ekki JSON sem hefur verið lesið og skrifað aftur. Svaraðu 401 ef það passar ekki.
- Bregðstu við subscription_contract.activated, .renewed, .changed, .canceled og .ended. Finndu notandann með data.reference, sem er contract_reference frá lið 1, og stilltu aðgang eftir data.service_active.
- Svaraðu 200 fljótt. Vinnslan verður að þola að sami atburður berist tvisvar.

5. ÖRYGGI
- ASKELL_SECRET_KEY og ASKELL_WEBHOOK_SECRET eru aðeins í umhverfisbreytum á þjóninum. Aldrei í vafra, logum eða git. Búðu til .env.example án gilda.
- Ef vefurinn notar Content-Security-Policy: script-src og style-src https://cdn.askell.is (style-src þarf líklega líka 'unsafe-inline'), connect-src og frame-src https://askell.is, og img-src https: fyrir vörumyndir.
- Lén síðunnar verður að vera nákvæmlega skráð í "Leyfð lén" sölurásarinnar, annars svarar Áskell 403 "Origin is not allowed for this checkout session."

SKILAÐU
- Öllum kóða fyrir mitt kerfi, með skráarheitum og hvar hver bútur á heima.
- .env.example með ASKELL_SECRET_KEY, ASKELL_WEBHOOK_SECRET og ASKELL_SALES_CHANNEL.
- Stuttum prófunarlista: kaup gegnum askrift-prof (hvaða kortanúmer sem er með 11–19 tölustöfum, CVV 322), staðfesting á þjóni, vefkrókur (Áskell sendir ekki vefkróka á localhost, notaðu t.d. ngrok), og svo skipti yfir í askrift.
Ef eitthvað vantar undir MÍNAR UPPLÝSINGAR, spurðu áður en þú skrifar kóða. Ekki nota aðra endapunkta eða reiti hjá Áskeli en þá sem eru nefndir hér. Ef þig vantar meira skaltu vísa í https://docs.askell.is/is/api/embedded_checkout.html og https://askell.is/api/swagger/v2/.

To get ASKELL_WEBHOOK_SECRET: Settings → Webhooks → Add a webhook. Choose Event: “All subscription contract events” (subscription_contract.*), put the address of route 4 in Url and click Save. Then open the webhook in the list. The secret is in the HMAC Secret field, and the Copy secret button copies it.

Common errors

Symptom

Cause

Fix

The sales channel is not listed on the payment page

The channel is a Draft

Set it to Active, the last item in step 3

“Please add at least one allowed origin before activating this channel.”

The channel has no origin

Add your website’s address

The buyer can choose both prices

Price selection is left at the default

Choose “exactly one price” and reload the page

The prices look the same in the widget

The prices have no Price description

Write a description for each price

The amount is higher than the price

VAT is added on top (Exclusive)

Set the tax rate to Inclusive

Widget: 403 “Origin is not allowed for this checkout session.” or the card window does not appear

The page’s domain is not exactly in Allowed origins: www, http/https or a trailing slash

Fix the origin and reload the page

Widget: 404 on the session

The session has expired or has already been used

Create a new session every time the widget is shown

400 on sales_channel when a session is created

The channel is not active, or the reference is wrong or digits only

Check the channel’s status and Reference

401 or 403 when a session is created

Wrong key, or the public key was used

Use the Private Key in the Api-Key header

“A customer with this reference already exists.”

The kennitala is already registered with a different email

The buyer uses the same email as before, or you correct the email on the customer

“Teya is not connected for this payment processor.”

The connection is missing or was disconnected

Step 1, items 7–9

Card registration or renewals always fail

The Teya store is not allowed to save cards or take merchant-initiated payments

Ask Teya to enable both

“Disconnect from Teya before switching between the staging and production environments.”

The switch was changed on a connected payment processor

Disconnect first, or create a new payment processor

“Could not start the Teya connection.” or an error that mentions TEYA_PLUGIN_TYPE

A setting on Áskell’s side

Contact Áskell

The payment page does not appear in an iframe

The page does not allow iframes

Use an ordinary link

A change to the sales channel does not show in the widget

Each session keeps a copy of the channel’s settings

Reload the page so that a new session is created